define-valuesの書き方

コメントを頂いた。

 (define-syntax define-values 
   (syntax-rules () 
     ((define-values () exp) 
      (call-with-values (lambda () exp) (lambda () 'unspecified))) 
     ((define-values (var . vars) exp) 
      (begin  
        (define var (call-with-values (lambda () exp) list)) 
        (define-values vars (apply values (cdr var))) 
        (define var (car var)))) 
     ((define-values var exp) 
      (define var (call-with-values (lambda () exp) list))))) 

これは一旦listにして分解する方法。たしかにこちらの方が多少書きやすいかもしれない。。
R6RS Schemeでは多少修正が必要で、

 (define-syntax define-values
   (syntax-rules ()
     ((define-values () exp)
      (call-with-values (lambda () exp) (lambda () 'unspecified)))
     ((define-values (var . vars) exp)
      (begin
        (define temp (call-with-values (lambda () exp) list)) ;; var → temp
        (define-values vars (apply values (cdr temp)))
        (define var (car temp))))
     ((define-values var exp)
      (define var (call-with-values (lambda () exp) list)))))

(define var ...)が一度しか表れないようにしないといけない。R6RSでは2重のdefineはできない。また、このままだとTop Level以外では使えないので、結局無駄な値をdefineする必要は有る。

 (define-syntax define-values 
   (syntax-rules () 
     ((define-values () exp) 
      (define bogus ;; defineに変える。
        (call-with-values (lambda () exp) (lambda () 'unspecified))))
     ((define-values (var . vars) exp)
      (begin
        (define temp (call-with-values (lambda () exp) list))
        (define-values vars (apply values (cdr temp)))
        (define var (car temp))))
     ((define-values var exp)
      (define var (call-with-values (lambda () exp) list)))))

一旦多値をlistに纏めないといけないのは、マクロのパタン変数で多値を取り扱えないため。そのかわり、set!を使わずに済むので、前のように変数をexportするために余計な変数を準備する必要はなくなる。
多値を分解せず、かつ、set!を使わない方法は存在しないように思える。

  • 多値を分解せずbindする方法はlambda(あるいはreceive)しかない
  • lambdaは常にスコープを作る

スコープを越える方法はset!しかない。と思う。

無効値のdefineのしかた

R6RSでは(define hoge)が有効という指摘があった。(define hoge)は、hogeに(いわゆる)undefinedを格納する。
というわけで、この手のマクロを書く必要があるときは、この形式のdefineを使ってもらうようにすれば最適化できるのかもしれない。。(未定義値をちゃんと値として持って普通の最適化を適用する手もあるが。。)