OCaml一人勉強会 - Lazy
さて任意の式 expr の遅延オブジェクトを返すような手続き lazy(expr) は書けるかというと、残念ながら書けません。引数を式のままとるような関数が OCaml では書けないためです。
幸いなことに OCaml には始めから lazy という式文法が存在し、それを使うことで実現できます。
# let output = lazy(print_endline "lazy :)");; val output : unit lazy_t = <lazy>
lazy_t は遅延オブジェクトの型です。
実際に値を計算するには Lazy モジュールの force を使います。
# Lazy.force output;; lazy :) - : unit = ()
はいふざけんなって感じですね。なんで lazy は予約語扱いなのに force だけ Lazy モジュールにあるんでしょう?
lazy が予約語扱いなのは多分実装の都合です。どうせなら対になる force も Pervasives (初期状態で open されるモジュール)に入れて問題ないと思うんですが…
さてこの lazy は前回やった遅延オブジェクト(ただの関数だけど)とは違うところがあります。それはメモ化の有無です。良く知りませんが。
メモ化というのは、既に計算した値を覚えておき、次に値が必要になった時は実際に計算を行わずに値を返す手法のことを言います。良く知りませんが。
あまりよくない例ですが、どういうものかを知ってもらうには分かりやすいので文字列の出力を遅延してみましょう。
# let output1 () = print_endline "lazy :)";; val output1 : unit -> unit = <fun> # let output2 = lazy(print_endline "lazy :)");; val output2 : unit lazy_t = <lazy> # output1();; lazy :) - : unit = () # Lazy.force output2;; lazy :) - : unit = () # output1();; lazy :) - : unit = () # Lazy.force output2;; - : unit = ()
組み込みの lazy を使った output2 は二度目の評価の際式の実行が行われなかったのが見てとれます。
これだけだと何のことやらという感じですが、計算に時間のかかる式を遅延する場合を考えてみて下さい。
さてあんまり詳しく触れようとすると詳しく無さが露呈するのでこの辺でやめときます。続きは偉い人の Web で…!