読者です 読者をやめる 読者になる 読者になる

続・名前空間

前回は Scheme (R6RS) のマクロを使って名前空間的なものを実現しようと試みた。
id:SaitoAtsushi:20100828:1282960407
それについて id:leque 氏より興味深いコメントを頂いた。

これは datum->syntax を使わなくても書けるように思います。

(define-syntax make-namespace
  (lambda (x)
    (syntax-case x (define)
      ((k name (define var val) ...)
       (with-syntax (((tmp ...) (generate-temporaries #'(var ...))))
         #'(begin
             (define tmp val)
             ...
             (define-syntax name
               (syntax-rules ()
                 ((_ n)
                  (letrec-syntax ((find
                                   (syntax-rules (n)
                                     ((_ (n . _) (v . _))
                                      v)
                                     ((_ (_ . ns) (_ . vs))
                                      (find ns vs)))))
                    (find (var ...) (tmp ...))))))))))))

変数名を作るのに generate-temporaries を使っていますが、ここも syntax-rules で書けば syntax-rules だけで書けます。

http://d.hatena.ne.jp/SaitoAtsushi/20100828/1282960407#c1282976093

このコメントを受けて試しに syntax-case や generate-temporaries を使わないように書き直してみた。

(define-syntax %make-namespace
  (syntax-rules (define)
    ((_ name (binds ...) (define (var args ...) val) next ...)
     (begin (define (tmp args ...) val)
            (%make-namespace name ((var tmp) binds ...) next ...)))
    ((_ name (binds ...) (define var val) next ...)
     (begin (define tmp val)
            (%make-namespace name ((var tmp) binds ...) next ...)))
    ((_ name (binds ...) exp next ...)
     (begin exp
            (%make-namespace name (binds ...) next ...)))
    ((_ name (binds ...))
     (define-syntax name
       (syntax-rules ()
         ((_ id)
          (letrec-syntax ((find
                           (syntax-rules (id)
                             ((_ (id v) next ((... ...) (... ...)))
                              v)
                             ((_  p next ((... ...) (... ...)))
                              (find next ((... ...) (... ...)))))))
            (find binds ...))))))))

(define-syntax make-namespace
  (syntax-rules ()
      ((_ name exp next ...)
       (%make-namespace name () exp next ...))))

MIT 記法も OK なのと、定義以外の式も書けるようにした。
が、ここで致命的な欠点が発覚。 make-namespace の内部では御互いに変数へアクセスできない。

(make-namespace ns
  (define a 1)
  (define b (+ a 1)) ;; ←これ駄目
  )

これではとても実用レベルにはなりそうもない。
ただ、アクセス不能な変数とそれに対するインターフェイスとしてのマクロというパターンは何かと使えそうな気がする。 その意味では先日のネタ (id:SaitoAtsushi:20100822:1282449327) と共通のパターンになっている。
Document ID: 3064c1bfec3f358f4a81cf8ab1669866