What is it, naokirin?

私の貧弱なOCaml力を晒す 第一回 「ローカルオーッ、\プンッ!/」

今回は私の貧弱ぅなOCaml力を晒すべく、最近知ったばかりのOCamlの知識を書いていこうと思います。自分が知らなかったOCamlネタが見つかり次第、随時記事として追加していくつもりです。

今回はlocal open。これは3.12で追加された機能ですね。まあ、知らなかったからどうだという話ではないですが、正直最新機能とか追いきれてないですorz

ちなみに今回書くlocal openはたまに「あー、ここopenしてぇ…でも、openしたら名前空間が…汚れて…グハァァッ!」というときに便利らしいです。

で、local openがどんなものかというと、

let open List in append [1] [2]

といった感じで単一の式に限定してopenするというもの。(例がとてもじゃないけどいい使い方とは思えないw)

構文としては

let open Module in expr

また、local openにはもう一つの構文があって

Module.(expr)

みたいな書き方もある。

これを見て思ったことが一つあって、演算子を使うときに使えそう、と思いました。
自分が作ったモジュールに演算子を組み込むとき、実装では別のモジュールの演算子を使うなんてことになったとすると、openしないと演算子としては使えないしopenすると自分の実装したい演算子と名前が衝突する、なんてことが起こるわけです。


もう少しマトモな例としては

module MyList = struct
  (* 正直, open Listでも問題ない *)
  let (<) l1 l2 = List.((length l1) < (length l2))

  ...

  (* (<)の演算子を定義したので, いつもの(<)を使うために
     Pervasive名前空間をlocal open *)
  let init f i =
    let rec recur i ls =
      if Pervasives.(i<n) then recur (i+1) ((f i)::ls)
      else ls
    in
    rev (recur 0 [])
  end

といった感じでしょうか。今回はModule.(expr)を使っていますが、もっと式の中で分散的に演算子を使ったりする場合にはlet open 〜 inの方がより見やすくなるかなと思います。

これを書いていて思ったのですが、これって演算子がいわゆる「記号は一文字で使われることも多く、かぶる率が高いから」ではないかと。つまりその他の関数でも一般的な名前の関数であれば衝突しやすくなるので、同じことが言えるのではないかと思いました。なのでいわゆる一般的な名前の関数をopenする時にも使えそうな気がしてきました。

書いてみたけど、正直こんな使い方でいいのだろうか…。不安を残したままではありますが、第一回はこの辺で。