kiyoka.2010_03_26 RSSPLAIN

Related pages: !kiyoka.blog.list !kiyoka.blog.2010_03
55545555555555555555545555555555555555555555555555555555555555555555555555555325
5

[Nendo] 多値の実装完了 

5

私がRubyで書いているLisp方言、 Nendoについて。

5

 

4

多値が動いた。(参考リンク: Scheme:多値EXT)

5

Chatonでつぶやいたら、さっそくShiroさんが答えて下さった。

5

 

5
 Gauche > Archives > 2010/03/24EXT 周辺のログを抜粋
5
 kiyokaの質問
5
  オレLisp処理系Nendoに多値を組み込みたいけど、どうやったらいいのか悩み中です。
5
  ちなみにNendoは継続とかサポートしていません。
5
  巷のSchemeライブラリのソースを流用したいことが多いので、できれば values と receive がそのまま動けばうれしいのですが...
5
 shiroさんからの回答
5
  >kiyoka 性能を考えないなら、guileがやってたように0個と2個以上の値を特別なオブジェクトにパックしてしまうってのでとりあえず動かすことはできますよ。
5
  受け取る値の個数を間違えた場合にその内部的な「多値オブジェクト」が見えてしまう、というのがちょっと残念ですが。
5
  (define (values . args) (match args [(val) val] [_ (make-values args)]))
5
  (define (call-with-values producer consumer) (let ((v (producer))) (if (values? v) (apply consumer (values-values v)) (consumer v))))
5
  多値オブジェクトは make-values で作成、values? で判断、 values-valuesで値リスト取り出し、と想定。
5
  (define-syntax receive (syntax-rules () ((receive vars expr body ...) (call-with-values (lambda () expr) (lambda vars body ...)))))
5

 

5

ほぼshiroさんの回答通り実装してみた。

5

残念ながらNendoには match と define-syntax がまだ装備されていないので、別の手段で実装してある。

4

make-values、values?、values-values は Rubyで書いてある。

5

 

5
ソースコード
5
(define (values . args)
5
  (case (length args)
5
    ((1)
5
     (car args))
5
    (else
5
     (make-values args))))
5
5
(define (call-with-values producer consumer)
5
  (let ((v (producer)))
5
    (if (values? v)
5
        (apply consumer (values-values v))
5
        (consumer v))))
5
5
;; srfi-8
5
(define receive
5
  (macro (vars expr . body)
5
    `(call-with-values
5
         (lambda () ,expr)
5
       (lambda ,vars ,@body))))
5

 

5
実行結果
5
R5RSの仕様書に書いてある例
5
nendo> (call-with-values
5
            (lambda () (values 4 5))
5
          (lambda (a b) b))
5
 => 5
5

 

5
nendo> (call-with-values * -)
5
 => -1
5

 

5
その他
5
nendo> (call-with-values
5
            (lambda () (values 1 2))
5
          cons)
5
 => (1 . 2)
5

 

5
nendo> (call-with-values
5
            (lambda () (values 10))
5
          list)
5
 => (10)
5

 

5
nendo> (receive all       (values)           all)
5
 => ()
5

この結果は実装依存だと思うが、Gauche 0.9と同じ動作になっている。

5

 

5
nendo> (receive (a . b)   (values 10 20 30)  (list a b))
5
 => (10 (20 30))
5

 

5

これで、Gaucheのtext.html-liteのポーティング準備が一歩前進した。

5

後は、keyword関連と list* を実装したら簡単にポーティング出来るんじゃないかと。

5

この作業のゴールとしては、Sinatraのページ記述用プラグインとしてhamlとかerb等があるが、その一つとしてS式でもページが書けることを狙っている。(Sinatraのソースを読んだら、プラグイン追加するためには、パッチを当てないとダメっぽいが...)

5

とりあえずの中間地点として、まずS式でCGIが書ける段階を目指そう。

5

 

3

COMMENTshiro

list*は簡単ですよ。 (define (list* arg . args) (if (null? args) arg (cons arg (apply list* args))))

2

COMMENTkiyoka

list* の定義は簡単なんですねー。ありがとうございます。

上記コードがNendoでも動きました。

nendo> (list* 1)

=> 1

nendo> (list* 1 2 3 4)

=> (1 2 3 . 4)

5

...comment disabled...