ピエールの綱渡り

すごいHaskellたのしく学ぼう! にMaybeモナドの説明で、次のようなものがあります。


ピエールがバランス棒を持って綱渡りしている最中、バランス棒の左右に鳥がとまる。
左右の鳥の数の差が3より大きくなったらピエールは落下して綱渡りが失敗する。
左右の鳥の数の差が3以下のままで最後までいけたら成功。


ということで、F#のコンピュテーション式で書いてみました。Maybeを表すだけだと物足りないので、以下のことをやってみました。

  • コンピュテーション式のBuilerに失敗していないことを判定する関数を渡せるようにする
  • let!ではなくdo!で書きつつ次の計算式に状態を渡せるようにする


利用部分を書くとこんな感じです。綱渡りを3回やっています。1回目は成功、2回目は左右の鳥の差が3を超えて失敗、3回目はバナナの皮に滑って失敗、という結果です。

let guard n = fun (left, right) -> abs(left - right) < n 
let tightrope = relay (guard 4)
 
let routine = tightrope {
  do! landLeft 1
  do! landRight 2
  do! landLeft 3 }
 
let routine2 = tightrope {
  do! landLeft 1
  do! landRight 2
  do! landLeft 5 }
 
let routine3 = tightrope {
  do! landLeft 1
  do! landRight 2
  do! banana
  do! landLeft 3 }

let print = function
  | Some(left, right) -> printfn "成功: %d, %d" left right
  | _ -> printfn "失敗"
do
  exec routine (Some (0, 0)) |> print  (* 成功: 4, 2 *)
  exec routine2 (Some (0, 0)) |> print (* 失敗 *)
  exec routine3 (Some (0, 0)) |> print (* 失敗 *)


シンプルに書けました!
コンピュテーション式には可能性を感じる!
Builderを書くのも読むのもしんどいけど。使う分には楽ですね。


コード全体はgistにあります。