構文糖衣: do記法
出典: フリー百科事典『ウィキペディア(Wikipedia)』 (2021/01/16 04:57 UTC 版)
「モナド (プログラミング)」の記事における「構文糖衣: do記法」の解説
bind 演算子 >>= を直接使ってプログラムを書くのがよい場合もあるが、典型的にはdo記法 (OCamlでは perform記法、F#ではコンピュテーション式)を使用し、命令型言語のような見た目にできる。コンパイラはdo記法の式を >>= を使ったものに変換する。例えば a = do x <- [3..4] [1..2] return (x, 42) を変換した結果は以下となる。 a = [3..4] >>= (\x -> [1..2] >>= (\_ -> return (x, 42))) リストモナドの実装を見てみよう。リストにマップを行い結合を行う(平らにする)この関数は concatMap とも呼ばれる。 instance Monad [] where m >>= f = concat (map f m) return x = [x] fail s = [] よって、以下のような変形が行われて、それぞれの式はすべて等価である。 a = [3..4] >>= (\x -> [1..2] >>= (\_ -> return (x, 42)))a = [3..4] >>= (\x -> concatMap (\_ -> return (x, 42)) [1..2] )a = [3..4] >>= (\x -> [(x,42),(x,42)] )a = concatMap (\x -> [(x,42),(x,42)] ) [3..4]a = [(3,42),(3,42),(4,42),(4,42)] リスト[1..2]は使われないことに注意しよう。左矢印をつけないことで、連鎖した関数は引数を無視するように変換されて、値ではなくモナド的な構造だけが問題になることを示すことができる。例えば、状態モナドで値を生成せずに状態だけを変化させるようなときに使われる。do記法は >>= の単なる構文糖衣であるので、どんなモナドに対しても使うことができる。 Maybeモナドの値を安全に割り算する以下の定義も等価である。 x // y = do a <- x -- xとyの中に値がある場合は取り出す b <- y if b == 0 then Nothing else Just (a / b)x // y = x >>= (\a -> y >>= (\b -> if b == 0 then Nothing else Just (a / b))) 同様にF#ではコンピュテーション式を使うことができる。 let readNum () = let s = Console.ReadLine() let succ,v = Int32.TryParse(s) if (succ) then Some(v) else Nonelet secure_div = maybe { let! x = readNum() let! y = readNum() if (y = 0) then None else return (x / y) } このmaybeブロックは構文糖衣であり、以下の式に変換される。 maybe.Delay(fun () -> maybe.Bind(readNum(), fun x -> maybe.Bind(readNum(), fun y -> if (y=0) then None else maybe.Return(x / y))))
※この「構文糖衣: do記法」の解説は、「モナド (プログラミング)」の解説の一部です。
「構文糖衣: do記法」を含む「モナド (プログラミング)」の記事については、「モナド (プログラミング)」の概要を参照ください。
- 構文糖衣: do記法のページへのリンク