OCaml4.08のmonadic/applicative let/andについて
OCaml4.08でシンタックスシュガーとしてlet*
、let+
、and+
などの構文が新たに導入された。
詳細については
がわかりやすかった。
直接モナドやApplicativeをサポートする構文というよりは、
let (let*) x f = g x f
などと好きに定義すれば
let* x = a in h x
が脱糖されて
g a (fun x -> h x)
になる、ということのようだ。モナドだったらlet (let*) x f = bind x f
、Applicativeだったらlet (let+) x f = map f x
にすればうまくいく。
let (let+) x f = map f x let (let*) x f = bind x f let+ x = a in g x (* desugars to map (fun x -> g x) a *) let* y = b in h y (* desugars to bind b (fun y -> h y) *) (* or alternatively b >>= (fun y -> h y) *)
しかし、and+
がどう脱糖されるのかいまいちピンとこなかった。
基本的にlet+
、and+
はApplicativeのために使われることが期待されており
let (let+) x f = map f x let (and+) xa ya = product xa ya
と定義するのが正しいようだ。
product
というのはApplicativeと同一の表現力を持つMonoidal Functorの関数で
val product : 'a t -> 'b t -> ('a * 'b) t
という型を持つ。つまり「Functorに入った値」二つを「一つのFunctorに入ったタプル」に変換する関数だ。
それがどう
let+ x = a and+ y = b in h x y
みたいな構文とつながるのか。調べてみたところこの構文を入れたPRにこんなコメントがあった:
The unmixed applicative case needs to translate:
let+ x = a
and+ y = b
and+ z = c in
body
into
map (fun ((x, y), z) -> body) (prod (prod a b) c)
let+ ... and+ ... and+ ... in ...
はまずlet+ ... ... ... in
の部分でApplicativeのproductを使ってネストしたタプルの入ったFunctorを作り、それに対して「引数をdestructureして使う関数」をin ...
の部分から作成して適用している。なるほど?
この構文はなかなか便利そうで、これを使って近々Graham HuttonのProgramming in Haskellに出てくるMonadic Parserを実装してみたい。