ラムダ式からの変換

Schemeラムダ式に対応するコンビネータ表記を求めるプログラムを作った。

使い方

lambdaをlambdaccにして、通常のlambdaと同じように引数と本体を与える。

gosh> (lambdacc (x y z) (x (y z)))
B
gosh> (lambdacc (x y) (x (y y)))
(C B M)

ソースコード

(use util.match)

(define-syntax lambdacc (syntax-rules ()
  ((_ var body ...) (uncurry (lcc 'var (curry '(body ...)))))))

(define lcc (match-lambda*
  ((() x) x)
  (((v . vs) x) (lcc v (lcc vs x)))
  ((v (x y)) (match `(,(in? v x) ,(in? v y))
    ((#f   #f)       `( K (,x ,y)))
    ((#f  'eq)          x)
    (('eq  #f)       `( T ,y))
    (('eq 'eq)         'M)
    (('eq (not #f))  `( O ,(lcc v y)))
    (((not #f) 'eq)  `( W ,(lcc v x)))
    ((#f    _)       `((B ,x)         ,(lcc v y)))
    ((_    #f)       `((C ,(lcc v x)) ,y))
    ( _              `((S ,(lcc v x)) ,(lcc v y)))))
  ((v x) (if (eq? v x) 'I `(K ,x)))))

(define in? (match-lambda*
  ((v (x y)) (if (or (in? v x) (in? v y)) 'in #f))
  ((v  x)    (if     (eq? v x)            'eq #f))))

(define (curry l)
  (if (pair? l) (currys (reverse l)) l))
(define currys (match-lambda
  ((x)                      (curry x))
  ((x . xs) `(,(currys xs) ,(curry x)))))

(define (uncurry l)
  (if (pair? l) (uncurrys l) l))
(define uncurrys (match-lambda
  ((xs x) `(,@(uncurrys xs) ,(uncurry x)))
  (    x  `(                ,(uncurry x)))))

バリエーション

なるべく後のパターンほど広くマッチするようにしたので、不要なパターンを削ればそれなりの動作をする。
例えば以下はSKIコンビネータのみの表記を求めるバージョン。

(define lcc (match-lambda*
  ((() x) x)
  (((v . vs) x) (lcc v (lcc vs x)))
  ((v (x y)) (match `(,(in? v x) ,(in? v y))
    ((#f   #f)       `( K (,x ,y)))
    ((#f  'eq)          x)
   ;(('eq  #f)       `( T ,y))
   ;(('eq 'eq)         'M)
   ;(('eq (not #f))  `( O ,(lcc v y)))
   ;(((not #f) 'eq)  `( W ,(lcc v x)))
   ;((#f    _)       `((B ,x)         ,(lcc v y)))
   ;((_    #f)       `((C ,(lcc v x)) ,y))
    ( _              `((S ,(lcc v x)) ,(lcc v y)))))
  ((v x) (if (eq? v x) 'I `(K ,x)))))

実行結果

gosh> (lambdacc (x y z) (x (y z)))
(S (K S) K)
gosh> (lambdacc (x y) (x (y y)))
(S (S (K S) K) (K (S I I)))

対応表

v y yv
v Mv Tyv Oyv
x xv K(xy)v Bxyv
xv Wxv Cxyv Sxyv