CommonLispの"*"みたいなマクロ

CommonLispの*みたいなかんじのを考えた。健全じゃないから使えないけど。

(let$ (assoc 'Hanako '((Taro . 28) (Saburo . 19) (Hanako . 20)))
    (if $_ 
        (cdr $_)
        "Not Found")
    (print "Hanako's age : " $_))

(let (($_0 (assoc 'Hanako '((Taro . 28) (Saburo . 19) (Hanako . 20)))))
  (let (($_1 (if $_0
                 (cdr $_0)
                 "Not Found")))
    (let (($_2 (print "Hanako's age : " $_1)))
      $_2)))

例のifの中で2回$_を使っているが、そういう時プログラムがすっきりして便利だと思う。
あと、こういう使い方もできる。

(let$ (+ 1 2) (* 3 4) (+ $_0 $_1)) ; => 15

マクロ:

(use srfi-13)
(define-macro (let$ . arg)
  (define (str n) ; (str 13) => '$_13
    (string->symbol
     (string-concatenate
      (list "$_"
            (number->string n)))))
  (define ($_n n p) ; ($_n 10 '(+ ($_ 2) 3)) => '(+ ($_10 2) 3)
    (if (pair? p)
        (cons ($_n n (car p))
              ($_n n (cdr p)))
        (if (eq? p '$_)
            (str n)
            p)))
  (let loop ((n 0) (a arg))
    (if (null? a)
        (str (- n 1))
        `(let ((,(str n)
                ,($_n (- n 1) (car a))))
           ,(loop (+ n 1) (cdr a))))))

追記:
letrecで囲えばrecみたいにできた。

(letrec$ (lambda (x) (if (= x 1) 1 (* x ($_0 (- x 1))))) $_) => fact