局所関数

schemeにおいて関数定義はこのようにする。

(define f (lambda(arg) ほにゃらら))

つまり、関数であるオブジェクトを変数に束縛するという考え方である。しかし、冗長であることから、大抵の処理系ではもっと簡単に定義できる構文が使える。その構文を利用すれば上の例と同じことをこのように書ける。

(define (f arg) ほにゃらら)

この記法は単なる便宜であり、意味的な差は無いとされている。
で、にちゃんねるのscheme関連スレで、letrecでもこのような記法を使えないかという話が出ていた。

(letrec ((c (lambda (a b) (+ a b)))
         (l (lambda (a b) (c a (c b 0)))))
  (l 1 2))

これが、

(letrecf (((c a b) (+ a b))
          ((l a b) (c a (c b 0))))
  (l 1 2))

こう書きたいというわけだ。
それに対して私はこのように回答した。

(define-syntax letrecf
  (syntax-rules ()
    ((_ ((f b) ...)
        body ...)
     (let () (define f b) ... body ... ))))

で、今度はletに対してもこのようなバージョンを書いてみようと思って出来たのがこれ。

(define-syntax letf%
  (syntax-rules ()
    ((_ (body ...) (r ...))
     (let (r ...) body ...))
    ((_ (body ...) (r ...) ((var args ...) fbody) next ...)
     (letf% (body ...) (r ... (var (lambda(args ...) fbody))) next ...))
    ((_ (body ...) (r ...) (var obj) next ...)
     (letf% (body ...) (r ... (var obj)) next ...))
    ))

(define-syntax letf
  (syntax-rules ()
    ((_ (a ...) body ...)
     (letf% (body ...) () a ...))))

なんか不格好。補助マクロが外から見えてしまう。R6RSにsyntax-caseとかいう構文を導入することが検討されているらしいけど、それがあればもっと綺麗に出来るだろうか。なんてschemeのせいにしてしまう私。
Document ID: 3670efb1dffc1cd6ab19982d57875c61