pa_field: {foo}を{foo=foo}にするCamlp4拡張
将来のOCamlで{foo = foo}のかわりに{foo}と書けるようになるかも、というウワサがあるらしいです。
ステキな機能ですね。
ここ最近、
let f {foo=foo;bar=bar;baz=baz} = ...
みたいなコードをずっと書いてて嫌になってきたので、Camlp4で実現してみました。
antiquotationがうまく使えなくて、直接コンストラクタを呼んでますが、とりあえず動きます。
使い方
まず、コンパイルします。
$ ocamlc -pp camlp4oof -I +camlp4 -c pa_field.ml
じゃあ、使ってみましょう。
$ ocaml dynlink.cma camlp4o.cma pa_field.cmo # type pt = {x:int};; type pt = { x : int; } # let x = 42 in {x};; - : pt = {x = 42} # let f {x} = x;; val f : pt -> int = <fun>
あと-ppに渡せば、ocamlcやocamloptでも使えます。
$ ocamlc -pp camlp4oof -I +camlp4 -c pa_field.ml
ソースコード
OCaml's record syntax extension · GitHubからダウンロードできます。
一応、ソースコードも貼っておきます。
(* pa_field.ml To compile: ocamlc -pp camlp4oof -I +camlp4 -c pa_field.ml To use: ocamlc -pp 'camlp4o pa_field.cmo' example.ml or ocaml dynlink.cma camlp4o.cma pa_field.cmo {x; y} == {x=x; y=y} Example: # type pt = {x:int};; type pt = { x : int; } # let x = 42 in {x};; - : pt = {x = 42} # let f {x} = x;; val f : pt -> int = <fun> *) open Camlp4.PreCast module Id = struct let name = "pa_field" let version = "$Id:$" end module Field ( Syntax : Camlp4.Sig.Camlp4Syntax) = struct include Syntax let stream_peek_nth n strm = let toks = Stream.npeek n strm in try Some (fst (List.nth toks (pred n))) with Failure _ -> None let test_no_with = let rec test lev strm = match stream_peek_nth lev strm with | Some (KEYWORD "(" | KEYWORD "with" | KEYWORD "=") -> raise Stream.Failure | Some (UIDENT _ | LIDENT _ | KEYWORD ".") -> test (succ lev) strm | _ -> () in Gram.Entry.of_parser "test_no_with" (test 1) EXTEND Gram expr: LEVEL "simple" [ [ "{"; test_no_with; lel = label_expr_list; "}" -> Ast.ExRec (_loc, lel, Ast.ExNil _loc) ] ]; label_expr: [ [ id = label_longident -> Ast.RbEq (_loc, id,Ast.ExId (_loc, id)) ] ]; label_patt: [ [ id = label_longident -> Ast.PaEq (_loc, id, Ast.PaId (_loc, id)) ] ]; END end module M = Camlp4.Register.OCamlSyntaxExtension(Id)(Field)