ラムダ計算遊び用コード まとめ

昨日見つけたページに倣ってλ項の名前には全部頭に%をつけて、ついでに左から適用してく関数を%としてみた。
とりあえずxyzzySBCLで動いてるけど、真偽値の辺りちゃんとテストしてない。

; utility
(defun % (&rest arg)
  (reduce #'funcall arg))

(defun $ (&rest arg)
  (reduce #'funcall arg :from-end t))

; SUCC := λn f x.f (n f x)
(defvar %succ
  (lambda (n)
    (lambda (f)
      (lambda (x)
        (% f (% n f x))))))

; ZERO := λf x.x
(defvar %0
  (lambda (f)
    (lambda (x)
      x)))

(defvar %1
  (% %succ %0))

(defvar %2
  (% %succ %1))

(defvar %3
  (% %succ %2))

(defun cn (n)
  (do ((i 0 (1+ i))
       (f %0 (% %succ f)))
      ((= i n) f)))

; ADD := λn m f x.n f (m f x)
(defvar %add
  (lambda (m)
    (lambda (n)
      (lambda (f)
        (lambda (x)
          (% m f (% n f x)))))))

; MULT := λm n f.m (n f)
(defvar %mul
  (lambda (m)
    (lambda (n)
      (lambda (f)
        ($ m n f)))))

; POW := λm n.n m
(defvar %pow
  (lambda (m)
    (lambda (n)
      (% n m))))

; TET := λm n.n (POW m) one
;      = λm n.n (λk.k m) one
(defvar %tet
  (lambda (m)
    (lambda (n)
      (% n ($ %pow m) %1))))

; PRED := λn f x.n (λg h.h(g f)) (λu.x) (λu.u)
;       = λn f x.n ((λi g h.h (g i)) f) ((λj u.j) x) (λu.u)
(defvar %pred
  (lambda (n)
    (lambda (f)
      (lambda (x)
        (% n
           (lambda (g)
             (lambda (h)
               ($ h g f)))
           (lambda (u) x)
           (lambda (u) u))))))

; SUB := λm n.n pred m
(defvar %sub
  (lambda (m)
    (lambda (n)
      (% n %pred m))))

; MOD := λm n.ISZERO (SUB m n) (ISZERO (SUB n m) ZERO m) (MOD (SUB m n) n)
;      = λm n.(λp.p (ISZERO (SUB n m) ONE ZERO)
;                     (p FALSE DIV (MOD m n) n)) (ISZERO (SUB m n))
(defvar %mod
  (lambda (m)
    (lambda (n)
      (funcall
       (% (% %iszero (% %sub m n))
          (lambda () (% %iszero (% %sub n m) %0 m))
          (lambda () (% %mod (% %sub m n) n)))))))

; DIV := λm n.ISZERO (SUB m n) (ISZERO (SUB n m) ONE ZERO) (SUCC (DIV (SUB m n) n))
;      = λm n.(λp.p (ISZERO (SUB n m) ONE ZERO)
;                     (SUCC (p FALSE DIV (SUB m n) n))) (ISZERO (SUB m n))
(defvar %div
  (lambda (m)
    (lambda (n)
      (funcall
       (% (% %iszero (% %sub m n))
          (lambda () (% %iszero (% %sub n m) %1 %0))
          (lambda () (% %succ (% %div (% %sub m n) n))))))))


; TRUE := λx y.x
(defvar %t
  (lambda (x) (lambda (y) x)))

; FALSE := λx y.y
(defvar %f
  (lambda (x) (lambda (y) y)))

; AND := λp q. p q FALSE
(defvar %and
  (lambda (p)
    (lambda (q)
      (% p q %f))))

; OR := λp q. p TRUE q
(defvar %or
  (lambda (p)
    (lambda (q)
      (% p %t q))))

; NOT := λp. p FALSE TRUE
(defvar %not
  (lambda (p)
    (% p %f %t)))

; XOR := λp q. p (NOT q) q
(defvar %xor
  (lambda (p)
    (lambda (q)
      (% p (% q %f %t) q))))

; IFTHENELSE := λp x y. p x y
(defvar %if
  (lambda (p)
    (lambda (x)
      (lambda (y)
        (% p x y)))))

; ISZERO := λn.n (λx.false) true
(defvar %iszero
  (lambda (n)
    (% n ($ %t %f) %t)))


; GE := λm n.ISZERO (SUB m n)
(defvar %ge
  (lambda (m)
    (lambda (n)
      ($ %iszero (% %sub m n)))))

; LE := λm n.GE n m
(defvar %le
  (lambda (m)
    (lambda (n)
      (% %ge n m))))

; EQUAL
(defvar %eq
  (lambda (m)
    (lambda (n)
      (% %and (% %ge m n) (% %ge n m)))))


; CONS := λf r b.b f r
(defvar %cons
  (lambda (f)
    (lambda (r)
      (lambda (b)
        (% b f r)))))

; CAR := λp.p true
(defvar %car
  (lambda (p)
    ($ p %t)))

; CDR := λp.p false
(defvar %cdr
  (lambda (p)
    ($ p %f)))

; Y-combinator
(defvar %y
  (lambda (g)
    ($ (lambda (x)
         ($ g (lambda (&rest arg) (apply ($ x x) arg))))
       (lambda (proc)
         ($ g (lambda (&rest arg) (apply ($ x x) arg)))))))

参考

Yコンビネータの解説は色々あったけど、これが一番分かりやすかった。