kiyoka.2011_04_06 RSSPLAIN

Related pages: !kiyoka.blog.list kiyoka.2011_04_17 !kiyoka.blog.2011_04
5555555555555555555555555555545553555555555554555555555555555555555555555555555555555555555555555555555
5

[Nendo][Scheme] syntax-rulesが動いた日

5

オレ処理系のNendoについての開発メモ。

5
 SYKjVO
5

chibi-scheme 0.3のer-macro-transformerとsyntax-rulesをそのままNendoに移植を試みていたのだが、ついに成功した。

5

 

5

make-syntactic-closureの実装方法は別段難しくなかった。

5

トップレベルにbindされた変数なら、その識別子をシンボルで返し、そうでなければ(gensym)したシンボルを返せばいいだけだった。

5

Rubyで書いた関数なので、これだけでは意味がわからんだろうけど、雰囲気だけでも伝わるかと思うので、コードを貼っておく。

5
    def _make_MIMARKsyntactic_MIMARKclosure( mac_env, use_env, identifier )
5
      if _pair_QUMARK( identifier )
5
        raise RuntimeError, "Error: make-syntactic-closure requires symbol only..."
5
      else
5
        if mac_env.to_arr.include?( identifier )
5
          identifier
5
        else
5
          sym = toRubySymbol( identifier ) + _gensym( ).to_s
5
          sym.intern
5
        end
5
      end
5
    end
5

 

5

 

5

苦労した主な敗因は、chibi-schemeのsyntax-rulesの定義を自分がよく理解しないままポーティングしようとしていたことだ。

5

こんな複雑な手続きが、一発で動くほど甘い世界ではない。

5

結局、デバッグコード挿入しつつ少しづつ原因を追いこんでいった。

5

 

5

 

5

Nendoにポーティングする時に考慮する必要があったのは以下の点。

5

 

4

... というシンボルをあらかじめグローバルに定義しておく必要があった

5

syntax-rulesを評価する直前に、次のような定義を置いた。

5
(define ... '...)
5

 

3

NendoのScheme非互換仕様に対しての手当が必要だった

5

マクロ展開時 v.1 や v.2 のようなローカル変数を抑制する必要があった。

5

Nendoには instance.method の様な表記をRubyのメソッド呼び出しとして特別扱いしている。

5

(これは、Schemeとは非互換な部分である)

5

 

5

Nendoでは syntax-rulesで展開したコード中の v.1 などの形式が vというインスタンスの1というメソッド呼び出しになってしまう。

5

まあ、数値リテラルのメソッドなんてものは無いので、v.1のような表記は特別に:"v.1"というシンボルとして扱えばいいのだけど、そういう例外も気持ち悪いので特例は入れないつもり。

5

結局 v__1 や v__2 のような変数名を生成するように変更した。

5
 (rename (string->symbol (string-append "v." (number->string count)))))
5

5
 (rename (string->symbol (string-append "v__" (number->string count)))))
5

 

4

chibi-scheme 0.3のany関数にバグがあった。

5

chibi-scheme 0.3のsyntax-rulesの定義中で何回か any が使用されているが、実はchibi-schemeのanyにはバグがある。(これは、chibi-schemeのMLでバグ報告しないといけない)

5

これを見つけるのに苦労したのだよ。

5

次のような場面で使われている。

5
(define-syntax syntax-rules
5
  (er-macro-transformer
5
      .
5
      .
5
             (cond
5
              ((any (lambda (v) (compare t (car v))) vars)
5
               => (lambda (cell)
5
                    (if (<= (cdr cell) dim)
5
                        t
5
                        (error "too few ...'s"))))
5
              (else
5
               (list _rename (list _quote t)))))
5
      .
5
      .
5

anyで見つかったcellを使って、(cdr cell)とかしちゃっているが、これは間違い。

5

本来のanyは条件にマッチした値を返すわけではなく、リスト中に条件を満たすものが1件でもあれば #t を返す。

5

要はchibi-schemeのanyはfindの動作をしちゃっているようだ。

5

 

5

証拠を示そう。

5

SRFI 1: List Libraryのanyの定義EXT

5
    Note the difference between find and any -- find returns the
5
    element that satisfied the predicate; any returns the true value
5
    that the predicate produced.
5
    (any integer? '(a 3 b 2.7))   => #t
5
    (any integer? '(a 3.1 b 2.7)) => #f
5

 

5

とうわけで、このように修正した。

5
 誤り:
5
              ((any (lambda (v) (compare t (car v))) vars)
5
 正解:
5
              ((find (lambda (v) (compare t (car v))) vars)
5

 

5

参考:

5
 $ chibi-scheme
5
> (any even? '(1 2 3 4))
5
2
5
5
 $ gosh
5
gosh> (any even? '(1 2 3 4))
5
#t
5
5
 $ nendo
5
nendo> (any even? '(1 2 3 4))
5
#t
5
nendo> (use srfi-1)
5
20000
5
nendo> (any even? '(1 2 3 4))
5
#t
5

 

5

さて、これでsrfi-2とかGaucheのutil.listがポーティングできるぞー。

5

Nendoでできる世界がさらに広がること間違いナシ。

5

高い壁をひとつ越えた気がする。すごい充実感。

5

 

5

...comment disabled...