SMLの演算子でセクションとbacktick notationを実現する

Haskellにはセクションという機能があって,
ラムダ式を書かずに中置演算子を引数の片方のみに適用することが出来ます.

Prelude> 5 - 2
3
Prelude> (-) 3 5
-2
Prelude> (7 -) 3 {- 左側に7を渡す -}
4
Prelude> (- 4) 8 {- 右側に4を渡す -}
4

これはSMLでは出来ませんが, 以下のような演算子を定義するとそれっぽく記述できます.

infix   4  <\
infixr  4  />
fun x <\ f = fn y => f (x, y)
fun f /> y = fn x => f (x, y)

e.g.
- (7 <\ op-) 3;  (* 左側に7を渡す *)
val it = 4 : int
- (op- /> 4) 8;  (* 右側に4を渡す *)
val it = 4 : int

あたまいいですね.

backtick notation

Haskellでは`(backtick)で関数を囲うと…

Prelude> let add x y = x + y
Prelude> 1 `add` 2 `add` 3
6

このように中置演算子として振舞わせることが出来ます.(あぁ妬ましい…)


これを実現するため, SMLでもおなじみのパイプ演算子を定義します.

infix   4  \>
infixr  4  </
fun f \> y = f y (* Haskell.$ *)
fun x </ f = f x (* F#.|>     *)

すると…

- fun add (x,y) = x + y; (* 足し算を定義 *)
val add = fn : int * int -> int
- 1 </add/> 2 ;
val it = 3 : int
- 1 </add/> 2 </add/> 3 ;
val it = 6 : int
- 1 </add/> 2 </add/> 3 </add/> 4 ;
val it = 10 : int

backtick notation(偽)が実現できました!!


適用の順序を見てみると,

e0 </ f0 /> e1 </ f1 /> e2 </ f2 /> e3 </ f3 ... /> eN
は
f0(e0, f1(e1, f2(e2, f3(e3,... ,eN))))

となり,

e0 <\ f0 \> e1 <\ f1 \> e2 <\ f2 \> e3 <\ f3 ... \> eN
は
f3 (f2 (f1 (f0 (e0, e1), e2), e3), ... eN)

となり,つまりそれぞれfoldr/foldlとなります!