otoha
(2008/07/13 05:09:27 PDT)
Ypsilon
暇さえあればGaucheのソースを読んでいた時期のことを思い出しつつ
某所で知ったR6RSな処理系Ypsilonのソースを読んでみる。
ベンチマークの結果、GCの実装など興味深い。
(2008/03/03 08:12:04 PST)
Anarki:[]
オフィシャルの方のArcは、tar玉がポンと公開されるだけなので、ユーザー達は そのソースをコネコネしていろいろ試している。 []には拡張が入って、Gaucheのcutとpa$を合わせたものになっている。
arc> (macex '[_3 _2 _1 __]) (fn (_1 _2 _3 . __) (let _ _1 (_3 _2 _1 __))) arc> (macex '[+ 1]) (fn gs1699 (apply + 1 gs1699))
[]の本体に`_'が現れない場合は部分適用になる。
(2008/02/22 15:07:38 PST)
構文糖
思えば、Schemeを覚えたのはArcのためだった。 今ではすっかりSchemeで考えるようになってしまって、Arc に馴染めない。 Arcには関数内関数をすっきり書けるように、rfn、afn、[... _ ...]などが 用意されてる。 SRFIにはrfn相当のrecがあるが、これって使いやすいだろうか? 使ってるコードをあまり見かけない。 もうnamed-letと内部defineに慣れてしまった。
;; これ、読みやすい? (def set-array! (a tree) (let rec (rfn rec (rank lst idx) (if (is rank 0) (<- (a (rev idx)) lst) (let count -1 (each l lst (rec (- rank 1) l (cons (++ count) idx)))))) (rec (a 'rank) tree nil)))
- Shiro(2008/02/22 16:31:32 PST): 上の例もそうなんですが、(Schemeの)recが
出る場面って、定義した関数を直ちに呼び出すパターンが多いんですよね。
こういう感じ:
((rec f (arg ...) body ...) init ...)
で、これならnamed-letの方が見やすいなと思っちゃいます。 recが有効なのは、再帰的な関数を作ってすぐ返すか、 すぐ引数として他の関数に渡すかって場合だと思うんですが、 あまりそういう場合に当たったことが無いような。
- otoha(2008/02/22 16:54:13 PST): 結局letで束縛を作ってしまうケースが多くて、これらによって コードが短くなることは少ないかもしれませんね。
(2008/02/13 07:23:47 PST)
Arc1
arc> =.a.1.b.2.c.3 3 arc> list.a.b.c (1 2 3)
面白すぎる。
(2008/02/11 10:10:10 PST)
call/cc
gosh> (call/cc (lambda (k) (k))) #<undef> gosh> (call/cc (lambda (k) (k 'foo))) foo gosh> (call/cc (lambda (k) (k (values)))) #<closure #f>
うーむ、、、なぜクロージャが返るのかな?
gosh> (disasm (call/cc (lambda (k) (k (values))))) main_code (name=#f, code=00AEAC00, size=5, const=0, stack=4): args: #f 0 VALUES(0) ; (values) 1 PUSH 2 LREF0 ; k 3 TAIL-CALL(1) ; (k (values)) 4 RET #<undef>
- 齊藤(2008/02/11 17:34:57 PST):(disasm (lambda(k)(k (values))))でも同じ結果が返ってきますね。(values)では値が無いのでその前にスタックに積まれた値を返してしまってるんじゃないでしょうか。想像ですけど。
- Shiro(2008/02/11 19:06:02 PST): すごく厳密なことを言うと、(k <expr>) の <expr>の部分というのはひとつの値を期待しているのに、(values) が返すのはゼロ個の値なのでその時点でエラーになるべきではあるんですね (これはcall/ccとは関係なく、「手続きの引数に現れる式は一つの値を返す」 という一般的なルールから導かれることです)。 ただ、この振る舞いはR5RSでは未定義ですし、Gaucheでは使う人が わかって使ってることを前提に、エラーチェックで速度を落とすことの 方を避ける方針です。ここでクロージャが返ることについては 「それは未定義動作。今回はたまたまクロージャが返ったが、 今後にわたって同じ動作をする保証はない」と考えてください。
- otoha(2008/02/12 03:51:36 PST): なるほど、未定義動作ですか。了解です。
(2008/02/06 17:30:18 PST)
Arcの[]
一引数の手続きはよく使うから、こんな感じの手続き
(lambda (x) (+ x 1))
は、Arcでは
[+ _ 1]
と書けるそうですが。でも、、、Schemeでは、それと同じくらいwith-* 系の高階関数に渡すthunk
(lambda () body ...)
をよく使う。これを
[body ...]
こう書けたら幸せかも。一引数に限定しちゃうのかな?
- gaucheでも (cut body ...)っていう書き方はありますけどね。
- Shiro(2008/02/06 17:41:55 PST): ひとつのアイディアは、{...} = (lambda () ...) とすることです。実は以前ちょっとだけ試してみて、どうも()と{}が 混ざってるのが気持ち悪くて止めちゃったんですが、 最近はR6RS風に[]を適宜使うようになったんで、また入れてみると 印象が違うかもしれません。