内部defineを作る

Lispを内部defineに対応させてみた。

repl> (letrec () (define x 1) (define y 2) (cons x y))
(1 . 2)

http://kar.s206.xrea.com/lisp/?e=(letrec%20()%20(define%20x%201)%20(define%20y%202)%20(cons%20x%20y))

以下のような展開処理をしてる。

(letrec () (define x 1) (define y 2) (cons x y))
↓
(letrec ((x 1)) (define y 2) (cons x y))
↓
(letrec ((y 2) (x 1)) (cons x y))
↓
(let ((y #f) (x #f)) (set! y 2) (set! x 1) (cons x y))
↓
((lambda (y x) (set! y 2) (set! x 1) (cons x y)) #f #f)

letrecとlambdaのコード

(define (eq-car? xs val)
  (and (pair? xs) (eq? (car xs) val)))

(define-macro (letrec arg . body)
  (if (eq-car? (car body) 'define)
    `(letrec ,(cons (cdr (macroexpand (car body))) arg) ,@(cdr body))
    `(let ,(map (lambda (x) (list (car x) #f)) arg)
       ,@(map (lambda (x) (list 'set! (car x) (cadr x))) arg) ,@body)))

(define-macro (lambda arg . body)
  (if (eq-car? (car body) 'define)
    `(new Closure ,arg (letrec () ,@body))
    `(new Closure ,arg ,@body)))

lambdaがマクロになったために,プリミティブの(lambda ...)の機能は(new Closure ...)で呼び出すようにした。
ちなみに,(new Macro ...)が従来の(macro ...)相当。