Lazy Pattern

このページは最後に更新されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

last mod. 2008-12-19 (金) 14:30:49

OCaml 3.11からはlazyパターンが導入されました。 まずはOCamlの遅延計算がどのようなものであるか、どのような問題点があったかを簡単に解説します。そして、lazyパターンを導入したことによって、どのように解決されるかを解説します。

おさらい: OCamlの遅延計算

OCamlでは一般のプログラミングと同様に正格評価が行われますが、lazyキーワードによって遅延計算を行うことができます。 lazy (do_something ())によって計算が遅延され、 遅延された計算はLazy.forceによって評価されます。一度、評価した式の結果は保存されるので、複数回同じ式が評価されることはありません。

例えば、以下の例ではlet x = lazy (print_endline "hello");;を評価した段階ではhelloが出力されず、Lazy.force x;;を評価すると初めて出力されます。さらに、評価した結果は保存され二回目以降はそれが使われるので、再びLazy.force xを評価してもhelloは出力されません。

# let x = lazy (print_endline "hello");;
val x : unit lazy_t = <lazy>
# Lazy.force x;;
hello
- : unit = ()
# Lazy.force x;;
- : unit = ()

問題点:パターンマッチが煩雑

上記のような仕組みで十分に思えますが、このままではパターンマッチが煩雑になってしまいます。

例えば、(42,lazy [1;2;3])のようなintと遅延されたリストのタプルを考えて見ましょう。そしてこの型に対して、以下のような関数を定義します。

  • タプルの1つ目が0のときはtrueを返す
  • タプルの2つ目が空リストのときはtrueを返す
  • それ以外の場合は、falseを返す
let f =
  function
      (0,_) ->
        true
    | (_,xs) ->
        begin match Lazy.force xs with
            [] ->
              true
          | _::_ ->
              false
        end

わりと複雑になってしまいました。これは、パターンマッチで遅延されたリストの中身を見れないため、いったんLazy.forceをした上で、再度パターンマッチを行わなければならないためです。

lazyパターンの導入

この問題を解決するために、lazyパターンが導入されました。 lazyパターンはlazy <パターン>のように、パターンの前にlazyを前置することで利用できます。これは、Lazy.forceしてパターンマッチを行うのと同じ意味になります。

このlazyパターンを用いると、前述の例は以下のように書き直すことができます。

let f =
  function
      (0,_) ->
        true
    | (_,lazy []) ->
        true
    | (_,lazy (_::_)) ->
        false

先ほどの例と比較して、より簡潔に書くことができました。

まとめ

OCamlではlazyによって計算を遅延することが可能です。しかし、これまでのOCamlでは、遅延された計算に対してのパターンマッチが煩雑になってしまいました。

3.11で導入されたlazyパターンを用いることで、この遅延された計算に対してのパターンマッチがより簡潔に書けるようになりました。

新規 編集 添付