OCamlでモナドを楽しむ †

HaskellのMaybeモナドとかListモナドによるバックトラックとかは大変有用。 でも欲張ってモナドそのものをOCamlに導入しようとすると、色々と複雑になってくる。 そこで、camlp4を使ったモナド拡張を利用して、シンプルにモナドを楽しんでみる。

まずは環境作り。 †

monad拡張をダウンロードしてきたら、おもむろにmake。その後、

$ocaml -I +camlp4
     Objective Caml version 3.09.3
#load "camlp4o.cma";;
     Camlp4 Parsing version 3.09.3
#load "pa_monad.cmo";;

として準備OK

Maybeモナド †

まず定義。超簡単。

module MaybeM = struct
    let rec bind m f =
      match m with
        None -> None
      | Some v -> f v
  end;;
module MaybeM :
  sig val bind : 'a option -> ('a -> 'b option) -> 'b option end

使ってみる。

# let env key =
    try
      Some (Sys.getenv key)
    with
      _ -> None
  in
  let name =
    perform with module MaybeM in
    user <-- env "USER"; 
    host <-- env "HOST";
    Some (user ^ "@" ^ host)
  in
  match name with
    None -> "None\n"
  | Some n -> n ^ "\n";;
- : string = "ogasawara@blendy\n"

これでoption型も怖くない。

Listモナド &dagger;

Haskellのlistモナドと同等・そのままんま。

# module ListM = struct
    let return x = [x]  
    let rec bind m f =
     List.flatten (List.map f m)  
    let guard c =
      if c then
        return ()
      else
        []
  end;;
module ListM :
  sig
    val return : 'a -> 'a list
    val bind : 'a list -> ('a -> 'b list) -> 'b list
    val guard : bool -> unit list
  end 

バックトラックしてくれる。

# perform with module ListM in
    i <-- [1; 2; 3];
    j <-- [4; 5; 6];
    ListM.guard (i + j > 7);
    ListM.return (i, j);;
- : (int * int) list = [(2, 6); (3, 5); (3, 6)]

応用すると、OCamlには参照型もあるので、条件に合う中で最大のものとかも簡単に作れる。


トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS