LoginSignup
2
0

More than 3 years have passed since last update.

OCaml Upcoming Changes 2020: let punning

Last updated at Posted at 2020-12-11

この記事はML Advent Calendar 2020 12日目の記事です。

OCamlにそろそろ入りそうな機能を紹介します。

今回は、次の次のOCaml 4.13で入りそうな Syntax proposal: let punning by stedolan · Pull Request #10013 · ocaml/ocaml の紹介をします。


以前はOCamlでモナディックなコードを書こうとすると fun>>= で頑張らないといけなかったが、OCaml 4.08.0 で binding operators が入ったことでふつうのコードのような見た目で書けるようになった。1

binding operatorsがない時のコード(例はAll About Monadsによる):

(* 下準備。よくあるbind演算子 *)
module Option_ops = struct
  let ( >>= ) x f = Option.bind x f
end

let mother's_paternal_grandfather s =
  let open Option_ops in
  mother s >>= fun m ->
  father m >>= fun gf ->
  father gf

binding operatorsがある時のコード:

(* 下準備。 + をApplicative, * をMonadにする慣習 *)
module Option_syntax = struct
  let ( let+ ) x f = Option.map f x
  let ( and+ ) x y =
    match x, y with
    | Some x, Some y -> Some (x, y)
    | _, _ -> None
  let ( let* ) x f = Option.bind x f
  let ( and* ) = ( and+ )
end

let mother's_paternal_grandfather s =
  let open Option_syntax in
  let* m = mother s in
  let* gf = father m in
  father gf

今回紹介するlet punningは、さらに、 binding operatorの左辺と右辺が同じ場合、右辺を省略できるようにする。

let liftA2_opt f x y =
  let open Option_syntax in
  let+ x and+ y in
  f x y
(*
let listA2_opt f x y =
  let open Option_syntax in
  let+ x = x
  and+ y = y in
  f x y
と同じ意味
*)

これは、レコード式などで、フィールド名と変数名が同じ場合に { x = x } を省略して {x} と書けるrecord punningという機能に見た目が似ているため、 let punning と呼ばれている。

この構文を導入する動機は以下のような要因があると思う。

  1. f <$> x <*> y のような演算子を使う方法は、OCamlでは優先順位がいい感じにならないことが多いので、多引数関数の持ち上げが面倒臭い(ユーザーが演算子の優先順位を決められない)
  2. OCamlには型クラスがないので、語彙を増やそうとするとファンクタ頼りになって構文的に重い(上記のliftA2_optもbinding operatorを定義したモジュールを受け取るファンクタを定義して他の型にも対応したいところ)2
  3. 1., 2. から binding operator だけ用意しておいてベタ書きする機会が多い
  4. 慣習的にshadowingが好まれるので、文脈に包まれた値と文脈内の値の変数を同名にしがち(誤解がなければ)

提案段階ではbinding operatorでない素の let についても右辺を省略できるようにして、次のようなコードを書けるようにしようという話もあったが、さすがに気持ち悪いということでこちらは見送られた。

module N = struct
  open M
  let compare and equal and hash
(*
  上記2行で↓と同じ意味
  let compare = M.compare
  and equal = M.equal
  and hash = M.hash
*)
end

また、 binding operator 導入以前は拡張ノードを使って let%lwt のように ppx でモナディックな束縛を実現していた場合もあったので、こちらも同様に右辺が省略できるようになっている。


  1. ppx_letとかの話はひとまず措く。 

  2. Modular explicitsが入ればましになる? 

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0