Let's start Scheme

2010-07-16

どれが正しいんだ?

Schemeでdefine-syntaxの実装をしないといけないことに気づき、ちょっと調査。
単にマクロ展開のタイミングの話なのかな?

(import (rnrs))
(define (print x)
  (display x)
  (newline))

(define x 1)
(define (incf x . i)
  (if (pair? i)
      (begin (set! x (+ x (car i)))
      (print "procedure")
      x)
      (begin (set! x (+ x 1))
      (print "procedure")
      x)))
(print (incf x 2))

(define (test x i)
  (print (incf x i)))
(test x 1)

(print "define incf as define-syntax!")

(set! x 1)
(define-syntax incf
  (syntax-rules ()
    ((_ x) (begin (set! x (+ x 1)) x))
    ((_ x i) (begin (set! x (+ x i)) x))))
(print (incf x 2))
(test x 1)
こんなコードを、Chez(7.9.4)、Ypsilon(0.9.6-update3)、Mosh(0.2.5)に食わせてみる。

結果。
Chezは正常終了。最後の(test x 1)で展開されると思われてincfマクロは展開されず。
Ypisilonは最後の(test x 1)でincfの定義がない(多分、マクロで上書きされたから?)と怒る。
Moshはincfが複数定義されたといって例外。

それぞれの結果はこれ。
Chez
------------
procedure
3
procedure
2
define incf as define-syntax!
3
procedure
4
------------

Ypsilon
------------
procedure
3
procedure
2
define incf as define-syntax!
3

error: unbound variable incf

backtrace:
0 (incf x i)
..."D:/home/t.kato/test.scm" line 18
1 (test x 1)
..."D:/home/t.kato/test.scm" line 29
------------

mosh
------------
Condition components:
1. &who who: incf
2. &message message: "multiple definitions of identifier"
3. &syntax form: incf
subform: #f

Exception:
error in raise: returned from non-continuable exception

Stack trace:
1. throw:
2. (raise c): baselib.scm:943
3. apply:
------------

これだけバラバラだとどれが正しいのかわからない・・・

1 comment:

Anonymous said...

r6rs では再定義は禁止されています。
私の手元にある Petite Chez Scheme が 8.0 だったのでそれで試してみたところ「Exception: multiple definitions for incf in body」というエラーでした。
Ypsilon についても r6rs 準拠モード (コマンドラインオプションに -6 を付ける) では「error in top-level program: duplicate definitions」というエラーメッセージを出します。

Post a Comment