F# のコンピューテーション式の例
https://learn.microsoft.com/ja-jp/dotnet/fsharp/language-reference/computation-expressions
https://mzp.hatenadiary.org/entry/20110205/monad
code:sample.fs
// コンテナにラップするモナドを考える
type Container<'T> = Container of 'T
(*最終的にこんな使い方を想定する
container {
let! x = Container 10
let! y = Container 15
return x + y // Container 25 が返る
}
*)
上記を実現するコンピューテーション式
code:builder.fs
(*
まず、bind と return について
bind は let! に、return は return に対して展開される
bind のシグネチャは M<'T> * ('T -> M<'U>) -> M<'U>
これは、Monad の中にある値を別の型に変換するというやつ (Bind(m, f) の m は monad の略だと思われる)
let! をつけると Container が外れるイメージで、中で M<'T> の 'T を取り出す事ができる
厳密に書くと
ContainerBuilder.Bind(Container 10, fun x ->
ContainerBuilder.Bind(Container 15, fun y ->
ContainerBuilder.Return(x+y)
)
)
これは x は 'T として扱える
return は 'T -> M<'T> となる
Haskell における bind 演算子である >>= を定義することがある
モナド則は以下の通り
左単位元律: return x >>= f = f x
右単位元律: m >>= return = m
結合律: (m >>= f) >>= g = m >>= (\x -> f x >>= g)
*)
let (>>=) (m: Container<'a>) (f: 'a -> Container<'b>) : Container<'b> =
match m with
| Container y -> f y
type ContainerBuilder() =
member _.Bind(m, f) = m >>= f
member _.Return(x) = Container x
let container = ContainerBuilder()
container {
let! x = Container 10
let! y = Container 15
return x + y
} |> printfn "%A"
// Container 25
container.Bind(
Container 20, fun x ->
container.Bind(
Container 25, fun y ->
container.Return(x+y)
)
)
|> printfn "%A"
// Container 45
F# のコンピューテーション式のサンプルを読み解く で公式のコンピューテーション式について理解を進める
#dotnet #f# #functional-programming