チャーチ数の簡単な計算(Ruby)

WikipediaOCaml の項目を読んでいたら、OCaml ではチャーチ数の計算がきれいに書けることを知った。

let zero f x = x
let succ n f x = f (n f x)
let one = succ zero
let two = succ (succ zero)
let add n1 n2 f x = n1 f (n2 f x)
let to_int n = n (fun k -> k+1) 0
let _ = print (add (succ two) two)

ほう、さすがである。

では我が Ruby では似たようなことは可能であるのか。OCaml ほど簡潔ではないが、可能である。『アンダースタンディング・コンピュテーション』という名著を参考に書いてみる。

$ pry
[1] pry(main)> zero = -> f { -> x { x } }
=> #<Proc:0x000055918b649bb0@(pry):1 (lambda)>
[2] pry(main)> def to_integer(n) n.(-> k { k + 1 }).(0) end
=> :to_integer
[4] pry(main)> to_integer(zero)
=> 0
[5] pry(main)> succ = -> n {-> f {-> x { f.(n.(f).(x)) } } }
=> #<Proc:0x000055918b3654f8@(pry):5 (lambda)>
[6] pry(main)> one = succ.(zero)
=> #<Proc:0x000055918b7143b0@(pry):5 (lambda)>
[7] pry(main)> to_integer(one)
=> 1
[8] pry(main)> two = succ.(one)
=> #<Proc:0x000055918b7653a0@(pry):5 (lambda)>
[9] pry(main)> to_integer(two)
=> 2
[10] pry(main)> add = -> m {-> n { n.(succ).(m) } }
=> #<Proc:0x000055918b7b8528@(pry):10 (lambda)>
[11] pry(main)> to_integer(add.(succ.(two)).(two))
=> 5

うーむ、これが 3 + 2 か…。
 

何度でも書くけれども、名著である。この本はコード例が Ruby。もはやこういう本が Ruby で書かれることはなくなったな…。Ruby != Rails と思っておられる方にはおすすめである。もちろん、Rubyist だけに独占させておくのはもったいない本なのであるが。