多値の実装完了
私がRubyで書いているLisp方言、 [Nendo]について。
多値が動いた。(参考リンク: Scheme:多値) Chatonでつぶやいたら、さっそくShiroさんが答えて下さった。
Gauche > Archives > 2010/03/24 周辺のログを抜粋 kiyokaの質問 オレLisp処理系Nendoに多値を組み込みたいけど、どうやったらいいのか悩み中です。 ちなみにNendoは継続とかサポートしていません。 巷のSchemeライブラリのソースを流用したいことが多いので、できれば values と receive がそのまま動けばうれしいのですが… shiroさんからの回答
kiyoka 性能を考えないなら、guileがやってたように0個と2個以上の値を特別なオブジェクトにパックしてしまうってのでとりあえず動かすことはできますよ。 受け取る値の個数を間違えた場合にその内部的な「多値オブジェクト」が見えてしまう、というのがちょっと残念ですが。 (define (values . args) (match args (val) val _ (make-values args))) (define (call-with-values producer consumer) (let ((v (producer))) (if (values? v) (apply consumer (values-values v)) (consumer v)))) 多値オブジェクトは make-values で作成、values? で判断、 values-valuesで値リスト取り出し、と想定。 (define-syntax receive (syntax-rules () ((receive vars expr body …) (call-with-values (lambda () expr) (lambda vars body …)))))
ほぼshiroさんの回答通り実装してみた。 残念ながら[Nendo]には match と define-syntax がまだ装備されていないので、別の手段で実装してある。 make-values、values?、values-values は Rubyで書いてある。
- ソースコード ```lisp (define (values . args) (case (length args) ((1) (car args)) (else (make-values args))))
(define (call-with-values producer consumer) (let ((v (producer))) (if (values? v) (apply consumer (values-values v)) (consumer v))))
;; srfi-8 (define receive (macro (vars expr . body) `(call-with-values (lambda () ,expr) (lambda ,vars ,@body))))
- 実行結果
-- R5RSの仕様書に書いてある例
```lisp
nendo> (call-with-values
(lambda () (values 4 5))
(lambda (a b) b))
=> 5
nendo> (call-with-values * -)
=> -1
– その他
nendo> (call-with-values
(lambda () (values 1 2))
cons)
=> (1 . 2)
nendo> (call-with-values
(lambda () (values 10))
list)
=> (10)
nendo> (receive all (values) all)
=> () この結果は実装依存だと思うが、Gauche 0.9と同じ動作になっている。
nendo> (receive (a . b) (values 10 20 30) (list a b))
=> (10 (20 30))
これで、Gaucheのtext.html-liteのポーティング準備が一歩前進した。 後は、keyword関連と list* を実装したら簡単にポーティング出来るんじゃないかと。 この作業のゴールとしては、Sinatraのページ記述用プラグインとしてhamlとかerb等があるが、その一つとしてS式でもページが書けることを狙っている。(Sinatraのソースを読んだら、プラグイン追加するためには、パッチを当てないとダメっぽいが…) とりあえずの中間地点として、まずS式でCGIが書ける段階を目指そう。
コメント by shiro:
listは簡単ですよ。 (define (list arg . args) (if (null? args) arg (cons arg (apply list* args))))
コメント by kiyoka:
list* の定義は簡単なんですねー。ありがとうございます。
上記コードがNendoでも動きました。
nendo> (list* 1) => 1 nendo> (list* 1 2 3 4) => (1 2 3 . 4)
コメント by shiro:
listは簡単ですよ。 (define (list arg . args) (if (null? args) arg (cons arg (apply list* args))))