Arantium Maestum

プログラミング、囲碁、読書の話題

OCaml4.08のmonadic/applicative let/andについて

OCaml4.08でシンタックスシュガーとしてlet*let+and+などの構文が新たに導入された。

詳細については

jobjo.github.io

がわかりやすかった。

直接モナドや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にこんなコメントがあった:

github.com

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を実装してみたい。