*OCamlでモナドを楽しむ [#f8329a4b]

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

- [[monad拡張のページ:http://www.cas.mcmaster.ca/~carette/pa_monad/]]
-- 例によって有名人が作っている。
-- exceptionモナドとかイケてる。

**まずは環境作り。 [#n7962b19]

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モナド [#r7c56357]

まず定義。''超簡単。''
 module MaybeM = struct
     let 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

使ってみる。''perform''というのがmonad拡張のキーワード。
bind関数を呼び出してくれる。
 # 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モナド [#x7cf4a9f]

Haskellのlistモナドと同等・そのままんま。
 # module ListM = struct
     let return x = [x]  
     let 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には参照型もあるので、''条件に合う中で最大のもの''とかも簡単に作れる。

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