CommonLisp Scheme Part12
■ このスレッドは過去ログ倉庫に格納されています
0001デフォルトの名無しさん
NGNGPart1: http://piza2.2ch.net/tech/kako/987/987169286.html
Part2: http://pc.2ch.net/tech/kako/1002/10025/1002584344.html
Part3: http://pc.2ch.net/tech/kako/1008/10082/1008220265.html
Part4: http://pc.2ch.net/tech/kako/1016/10162/1016211619.html
Part5: http://pc3.2ch.net/tech/kako/1023/10230/1023091882.html
Part6: http://pc3.2ch.net/tech/kako/1031/10315/1031560687.html
Part7: http://pc5.2ch.net/tech/kako/1042/10421/1042167213.html
Part8: http://pc5.2ch.net/tech/kako/1058/10582/1058263391.html
Part9: http://pc2.2ch.net/test/read.cgi/tech/1069594582/
Part10: http://pc5.2ch.net/test/read.cgi/tech/1075630259/
Part11: http://pc5.2ch.net/test/read.cgi/tech/1091456033/
関連リンクは>>2-10あたり
0322デフォルトの名無しさん
NGNG破壊的操作が必要になるのであまり嬉しくないけど、
計算量的にそれが必要ならやればいいだけの話。
0324デフォルトの名無しさん
NGNGいえ、すんません。巣に帰りまつ(;´Д`)
0325デフォルトの名無しさん
NGNG0326デフォルトの名無しさん
NGNG(let loop ((l l) (r '()))
(if (null? l) (reverse r)
(loop (cdr l) (cons (car l) r)))))
(define (copy-list2 l)
(let loop ((l l) (c (lambda (x) x)))
(if (null? l) (c l)
(loop (cdr l) (lambda (x) (c (cons (car l) x)))))))
(define (copy-list3 l)
(if (null? l) '() (cons (car l) (copy-list3 (cdr l)))))
(define (copy-list4 l)
(let ((n '(())))
(let loop ((l l) (r n) (end n))
(if (null? l) (cdr r)
(begin (set-cdr! end (cons (car l) '()))
(loop (cdr l) r (cdr end)))))))
速度は
copy-list1 > copy-list4 >>> copy-list2 >>>>>> copy-list3
くらいでした。copy-list4 はなんで遅いんだろ。
0327デフォルトの名無しさん
NGNGリストの長さや処理系によっても随分違うものになるだろうから
それらを特定しない比較には意味が無いような
0328デフォルトの名無しさん
NGNGリストの長さを変えても傾向は変わらなかったのか?
0329デフォルトの名無しさん
NGNG(apply list l))
0330デフォルトの名無しさん
NGNGほんとですね。とりあえず、
(define (fact f n)
(if (= n 1) f (lambda (x) ((fact f (- n 1)) (f x)))))
(define (num-list n)
(let loop ((n n) (r '()))
(if (zero? n) r (loop (- n 1) (cons n r)))))
として
((fact copy-list1 X) (num-list Y))
みたいな感じで計ってみました。
Yを大きくすると copy-list4が速くなると思ったんですが、
copy-list1の方が速かったです。処理系は Gaucheです。
他の処理系でも試してみます。
0331デフォルトの名無しさん
NGNGcopy-list1,copy-list4がそれぞれどれくらいの時間でできるか計算してごらん。
copy-list1はgcの時間をのぞいたら変わらないと思うよ。
0332デフォルトの名無しさん
NGNG(let loop ((l l) (r '()))
(if (null? l) r
(loop (cdr l) (cons (car l) r)))))
(define (copy-list6 l) (my-reverse (my-reverse l)))
としたら copy-list4 > copy-list6 でした。
つまり copy-list1は組み込みのreverseを使っているから速いってことでしょうか。
リストの長さをNとすると copy-list1は 6N、copy-list4 は 5Nくらいの計算量に
なるんですかね。
0333デフォルトの名無しさん
NGNGちなみに Gauche組み込み対決では
list-copy と (lambda (l) (reverse! (reverse l)))
が互格でした。
こういうリスト全体の処理では組み込みの reverseを使った方がいいってことですね。
あとからリストの後ろに破壊的に要素を足していきたい場合は deque方式と。
0334デフォルトの名無しさん
NGNGそうです。
copy-list1は2回cdrをたどってるから2N、copy-list4はNで
reverseがどんなに速くても、copy-list1はNより速くならないと考えるかもしれないけど、
copy-list1は6N、copy-list4は5Nになる。
copy-list1の内reverseにかかる部分が3Nで、コンパイルしたら2倍から10倍で実行できるとすると
4.5Nから3.6Nで実行できるわけです。
実際にどれくらいの速度差で実行してるか調べてみたら?
0335デフォルトの名無しさん
NGNG0336デフォルトの名無しさん
NGNG(mapcar #'identity list))
mapcar って組み込みだろうから、ごちゃごちゃコード書くより一番速い気がする。
ご参考
http://www.lisp.org/table/style.htm#efficiency
0337デフォルトの名無しさん
NGNG0338デフォルトの名無しさん
NGNGコンパイルした方がいくない?
0339デフォルトの名無しさん
NGNG次のような感じで変換すればオーケーでしょうか?
letrecをまだ用意していないもので。
(let loop ((a foo)
(b bar)
(c baz))
body)
=>
(let ((loop #f)
(a foo)
(b bar)
(c baz))
(set! loop (lambda (a b c) body))
(loop a b c))
0340(define (´∀`) 'マターリ)
NGNG(lambda (f x) (lambda y (apply (x (f f x)) y)))
(lambda (loop) (lambda (a b c) body)))
foo bar baz)
0341デフォルトの名無しさん
NGNGfoo, bar, bazのスコープにloopが入ったらまずいんでない?
0342デフォルトの名無しさん
NGNG入るのでしょうか? 入らないように思えるのですが。
gosh> (define loop '|(゚∀゚)アヒャ|)
loop
gosh> (let ((loop #f) (a loop) (c (lambda () loop))) (list a (c)))
(|(゚∀゚)アヒャ| |(゚∀゚)アヒャ|)
0343デフォルトの名無しさん
NGNG一見しただけでは何が何やらですが、理解に努めてみました。
> (lambda (f x) (lambda y (apply (x (f f x)) y)))
これをF
> (lambda (loop) (lambda (a b c) body)))
これをL
とおくと
((F F L) foo bar baz)
になって、少し展開すると
((let (loop (F F L))
(lambda (a b c) body))
foo bar baz)
みたいになりますね。
このbodyの中でloopを呼ぶと((F F L) a b c) のに戻って繰り返すわけですね。
面白い。こういうのをストリームというんでしょうか。
0344デフォルトの名無しさん
NGNGホントですか?
Cygwin 1.5.12-1
と
Gauche0.8.3 と Gauche-gtk-0.4.1
だと
gauche-glib.cのmakeでエラーがでてしまいます。
どーやったらコンパイルできるようになるのでしょうか?
0345339
NGNG# いまんとこコンパイラを動かすにはGaucheが必要だったりするんですが
ところで自由変数を参照しない手続きを呼ぶ用語に困っているのですが、
何か適当な用語はあるでしょうか。
環境を持たないクロージャなんですが、組み込みの手続き(コンパイラが即値で
書き込む)を利用するので副作用があって関数とも呼びにくいのです。
ちなみに大域環境はありません。
0346デフォルトの名無しさん
NGNGこれからブートストラップしてくんだね。
ところで環境を持たないクロージャとは、単純にトップレベルで
作成するような関数のことかね?
すなわちその関数内部の変数参照がローカル内で完結している関数
という解釈でいいのかな。
それとも、環境を持たないクロージャというのを、
限定構文を使うなりで明示的に宣言して作成するということかね。
副作用がSchemeからは見えず、処理系の内部的な話なのであれば、
特に区別する必要もない気がするが。
明示的なものであれば、例えばCにトランスレートするのが前提の関数なら
cfuncとかcdefineとか機能や意図に基づいた名前を付けるぐらいしか
思いつかないが。
あとは既存の処理系の名前を漁ってみるしかないんじゃないかな。
0347339
NGNGどうもです。
> ところで環境を持たないクロージャとは、単純にトップレベルで
> 作成するような関数のことかね?
そうです。レキシカル変数(引数か、内部で積む環境フレーム上の変数)だけ
使うもののつもりでした。
0348デフォルトの名無しさん
NGNG0349デフォルトの名無しさん
NGNG次スレからは
http://swiss.csail.mit.edu/classes/6.001/abelson-sussman-lectures/
もテンプレに加えてちょ。 ビデオ講義がある。 居ながらにしてMITの講義が見れるぞ。
0350デフォルトの名無しさん
NGNG0351デフォルトの名無しさん
NGNGおれにはそんなの作る気力がない
まあ当面は>>2以降にだらだらでいいやね
0352デフォルトの名無しさん
NGNG他の講義のビデオも有ったりするの?
0353デフォルトの名無しさん
NGNGGauche 側の gauche.h の SCM_EXTERN から __declspec(dllimport) を削って
Gauche-gtk 側は libgauche-uvector をリンクするよう追加するだけ。
最近の ld と gcc なら dllimport は無くてもよしなにやってくれるから。
0354デフォルトの名無しさん
NGNG0355デフォルトの名無しさん
NGNGhttp://ocw.mit.edu/OcwWeb/index.htm
にMITの講義録やシラバスがあるが、ビデオは数えるほどしかない。 将来的には
もっとビデオを増やすらしい。
ここはLispスレだし、その方面のバイブルがタダで手に入って、かつ、講義まで全部見れるんだから
世の中便利になったと思います。
個人的にはSICPは冗長な気がする(特に、1〜3章)けど、4,5章は真面目に読む価値があると
思う。 実際に自分で手を動かして、Schemeのインタプリタやランタイム&コンパイラをJavaや
C++で実装するとホントに理解が深まる。 CSを勉強するときには実際に手を動かした時に学んだ
ノウハウが大きな財産になるから、暇な人はトライしてみる価値がある。
0356デフォルトの名無しさん
NGNG0357デフォルトの名無しさん
NGNG今年マリノスが勝って終わったやつ。
0358デフォルトの名無しさん
NGNG0359デフォルトの名無しさん
NGNG0360デフォルトの名無しさん
NGNG0361355
NGNGI'm a CS major at ** university. で通じるよ。
0362デフォルトの名無しさん
NGNG0363デフォルトの名無しさん
NGNG> ところで自由変数を参照しない手続きを呼ぶ用語に困っているのですが、
> 何か適当な用語はあるでしょうか。
「自由変数を参照しない手続き」といえばコンビネータだけど
ちょっとニュアンスが違うような気もしないでもない?
0364デフォルトの名無しさん
NGNGコンビネータは、普通はあまり副作用のないイメージが。
「閉じた式」(=自由変数のない式)の類推で、「閉じた手続き」じゃ駄目?
0365デフォルトの名無しさん
NGNG0366デフォルトの名無しさん
NGNG(define aaa "hello, world")
(define (bbb) 'aaa)
(ccc (bbb)) => "hello, world"
になるような手続きcccってあるんでしょうか。
evalしかないですか?
0367デフォルトの名無しさん
NGNG0368デフォルトの名無しさん
NGNGいけないんじゃない? sicpの4章を読みましょう。
0369366
NGNGとりあえずSICPも読んでみます。
0370デフォルトの名無しさん
NGNG0372デフォルトの名無しさん
NGNG副作用ももたないものを形容する言葉はありますか?
+や-などがその仲間だとおもいます。よろしくお願いします。
0373339
NGNG返事がおくれてすみません。
>>363,364
さすがにコンビネータはちょっとそぐわない気がいたします。
閉じた手続きはいいかも知れません。closed-procedureでしょうか?
>>348
そういうのは組込みの手続きを用意していてそれをコンパイラが埋め込みます。
初期化段階ではLisp/Scheme的な大域環境が(シンボルも)存在しないので。
>>372
それを関数(function)と呼ぶのではないでしょうか。
副作用があったり環境に依存するものを含めた総称がprocedureではないかと思います。
0374デフォルトの名無しさん
NGNG> それを関数(function)と呼ぶのではないでしょうか。
> 副作用があったり環境に依存するものを含めた総称がprocedureではないかと思います。
すみません、書き忘れました。Common Lispに限定しますと、規格書やコミュニティー内でも、
そのような区別はされていないようです。
(functionpなんてpredicateはそういう区別をしません。)
0375339
NGNG関数が手続き一般を指す場合、"pure function" というのが使われることが
多そうな気がします。元はfortran用語でしょうか。
0376デフォルトの名無しさん
NGNG0377デフォルトの名無しさん
NGNG(define (hoge x y) (cons x y))
(define (cons x y) ...)
はどう処理されるの?
0378339
NGNGいまのところ、そういうことはしない、というのが答です。
というのも、フルセットのScheme環境を用意するための「ローレベルScheme」
みたいなものが趣旨なので。シンボルも環境もこれを使って書くわけです。
# 今のところベクタも文字列もシンボルもありません
現状、大域変数はコンパイル単位で完結し、かつちょっと情けないですが1パスで
> (define (hoge x y) (cons x y))
ここでconsは組込み定数の参照("SCM_OBJ(&cons)"みたいな)に置き換えられ
> (define (cons x y) ...)
以降はconsに割り当てられた大域変数を参照します。
必要なら、lambda中の大域変数の操作をいったん擬似命令として出力する2パスで
今の条件でも(コンパイル単位で完結するのは変わりませんが)例のようなケースの
参照を普通のSchemeのようにできるとは思います。
今のところ大域変数の実体はコンパイル単位全体を包む最下段のレキシカル環境
フレームという身も蓋もない実装です。一段落ついたら、
defineされる大域シンボルのうち定義だけされるものと
変更されるものを区別して、後者のみCの変数を記憶場所に割り当て、
前者は定数化して参照を直接埋め込むようにする予定です。それが済めば
コンパイル単位間で大域変数を共有することも(必要性はともかく)できるはずです。
共通の大域環境を参照する普通のSchemeのコードをどうコンパイルするかは
そのうちシンボルや大域環境をローレベルschemeで書きながら決めます。
0379デフォルトの名無しさん
NGNGttp://www.cs.indiana.edu/dfried_celebration.html
0380デフォルトの名無しさん
NGNGSchemeで著明な人達の写真が見れるね。
Guy Steeleの顔ぐらいしか知らなかった。
0381デフォルトの名無しさん
NGNG0382デフォルトの名無しさん
NGNG0383デフォルトの名無しさん
NGNG小さくて速い処理系を探してまして、最も有望なBitとSECDR-Schemeのポインタが切れていたもので。
0384デフォルトの名無しさん
NGNG去年の話だけど。
0385デフォルトの名無しさん
NGNG何かお勧めのやつあれば教えてください。
サイトでも教科書でも構いませんので……
MLのスレで聞いたほうがいいのかな?
0386デフォルトの名無しさん
NGNG何かお勧めのやつあれば教えてください。
サイトでも教科書でも構いませんので……
MLのスレで聞いたほうがいいのかな?
0387デフォルトの名無しさん
NGNGMLの偉い人で、大堀先生の本はどうだろう。
共立出版 情報数学口座9「プログラミング言語の基礎理論」
http://www.jaist.ac.jp/~ohori/texts/index.html
この本に
形無しλ計算 → 型付きλ計算 → 多相型λ計算 → ML
の順番で説明されてたと思う。
0388デフォルトの名無しさん
NGNGその本にもあるかわかんないけど、
おれ論理式がよくわかんなかった。
でかい分数表記のやつ。
つーかあの辺理解できる気がしない。
実際どう動くかコードで示してほしかった・・・なんて無茶か。
0389デフォルトの名無しさん
NGNGttp://paw.s2.x-beat.com/up/img/4398.zip
zipの中身がSECDR-Scheme1.0.tgz
これのオリジナルが置いてあった場所はniftyだったと思う。
0390デフォルトの名無しさん
NGNGレスどうもありがとうです.
とりあえず図書館で探して読んでみるとです.
0391383
NGNG多謝。ドキュメントが詳しいのも良いっすな。
0392紫藤
05/01/18 11:24:21> Paul Graham, ANSI Common Lisp の練習問題の解答を載せた
>ホームページ等、ご存知でしたら教えていただけませんでしょうか
http://www.geocities.jp/shido_takafumi/pacl2.html
に書いたのでよろしかったら見てください。
せっかく書いたのに誰も見てくれないので宣伝します。
0393デフォルトの名無しさん
05/01/20 22:58:060394デフォルトの名無しさん
05/01/20 23:01:13おねがいします。
0395デフォルトの名無しさん
05/01/20 23:05:12とりあえず mini-schemeよりは速いはずです。
継続がなくて、マクロもどきや環境がファーストクラスです。
中間コードにコンパイルする方法を勉強して継続を実装したりしたいです。
http://primes.dnip.net/scheme.cpp
0396デフォルトの名無しさん
05/01/21 10:40:10たらい回ししてみようか…と思ったら、比較オペレータは定義されてなかった。
まだまだテスト版だからってことでしょうか。
ちょっと見てみると、scheme_oprtクラスとか無駄してるような…。
C++で実装するというのは、C使いの自分には面白かったです。がんばってください。
これだけのコードでまがりなりにも
処理系を作れてしまうというのが、Scheme(lisp)の良さですよね。
0397デフォルトの名無しさん
05/01/21 11:44:13比較オペレータなどを定義してみました。
scheme_oprtクラスは無駄してるでしょうか? よく分かんないです。
整数や真偽値や基本手続きをポインタではなく即値で埋めこむテクニックを知ったのですが
この先中間コードにコンパイルすることを考えると、今はどっちでもいいのかなあと思いました。
中間コードの話はSICP5章とドラゴンブック以外に参考になる文献はあるでしょうか?
特に継続の実装がさっぱり分からないです。
0398396
05/01/21 14:45:19わっ、反応早い!
scheme_oprtクラスのprintメソッドは、簡単なやり方でも、
とりあえず先にprintf("#<subr ")しておいて、if文でプロシージャ名をprintfして、
最後に">"をprintfしておいた方が、無駄な文字列データが減るはずです。
aplyメソッドも、プロシージャごとに完全なコード書かずに、汎用化するとか。
色んな意味でRHG(Ruby Hacking Guide)とGHG(Gauche Hacking Guide)は
役に立つと思いますが、すでに見ているか。
0399デフォルトの名無しさん
05/01/21 16:07:14printメソッドの話ですか。そこらへんは適当です。
Rubyのは少し見てましたが、Gaucheのは知りませんでした。
C++は細かいとこが直感的に分らないのでCで書きたくなってきました。
質問なんですが、手続き呼びだしの時、環境をコピーするより名前置き変えの方がいいですよね。
あと、SRFI-17の set!を実装するには全てのオブジェクトのサイズを同じにしないといけないんでしょうか?
0400デフォルトの名無しさん
05/01/22 01:57:46クロージャーの呼び出しでは引数を束縛して新しい環境を作るけど、これはコピーとはちょと違うし、名前の置き換えというのも何を意味しているのかちょとわからないなり。
>あと、SRFI-17の set!を実装するには全てのオブジェクトのサイズを同じにしないといけないんでしょうか?
SRFI-17のほうは例えば(define x "hogehoge") (set! (string-ref x 4) 3.14)みたいなことはエラーになるべきだから考えなくていいんじゃないかな。
0401デフォルトの名無しさん
05/01/22 03:00:08>クロージャーの呼び出しでは引数を束縛して新しい環境を作るけど、これはコピーとはちょと違うし、名前の置き換えというのも何を意味しているのかちょとわからないなり。
環境を壊したくないので、クロージャーを呼び出した時点での環境をコピーしてそれに引数の束縛を足して使うという意味です。
新しい環境を作るのにコピーはしないんでしょうか? 名前の置き変えは、環境は一つだけでかぶる引数の名前を全部置き変えるということです。
環境をリストで表現して先頭から新しい束縛を足して、検索するときは先頭から順番に調べるようにすれば、一つのポインタのコピーだけで済んで良いかなあと思いました。
ハッシュと違って検索に束縛の数に比例して時間がかかるのが欠点ですがどんなもんでしょうか。
>SRFI-17のほうは例えば(define x "hogehoge") (set! (string-ref x 4) 3.14)みたいなことはエラーになるべきだから考えなくていいんじゃないかな。
なんか勘違いしてました。ポインタの指す先を変更しないといけないのかと思ってました。
0402デフォルトの名無しさん
05/01/22 11:15:08>環境を壊したくないので、クロージャーを呼び出した時点での環境をコピーしてそれに引数の束縛を足して使うという意味です
ふむふむそういうことだったか....
最初に、クロージャーの呼び出し時にはその意味での環境のコピーはないなり。すでに存在する環境に引数から作った環境をリンクするだけなり。
次に、lambdaでクロージャーを作るときは環境をスタックからヒープに移動することはあるけれど、元のスタック上の環境は以後は使われなくなるなり。
>新しい環境を作るのにコピーはしないんでしょうか?
引数から新しい環境を作ったら以前の環境に対してリンクを張るだけなり。
このへんは >>3 の"Practical Scheme"が詳しい。
特に実装についてはその中の以下のページが素晴らしいなり。
ttp://www.shiro.dreamhost.com/scheme/stack-j.html
ttp://www.shiro.dreamhost.com/scheme/gauche/memo-stack-j.html
0403402
05/01/22 11:37:42「すでに存在する環境」はクロージャーの持っている環境のことなり。
>元のスタック上の環境は以後は使われなくなるなり
これは完全にゴミになるということなり(実際デバッグ時には"0xcafecafe"とかで破壊するとよい)
どうもShiroのようにはうまく説明できないのう。
0404デフォルトの名無しさん
05/01/22 12:00:500405デフォルトの名無しさん
05/01/22 12:36:55なるほど。ちょっと難しいですが、20%くらい分かった気がします。
名前を検索するときは envポインタからたどって、
一番下の環境->一個上の環境->もう一個上の環境 という風に探していくんでしょうか?
なんか効率が悪いような。環境一つ一つはハッシュなんでしょうか?
>次に、lambdaでクロージャーを作るときは環境をスタックからヒープに移動することはあるけれど、元のスタック上の環境は以後は使われなくなるなり。
なんで使われなくなるのか良く分からないです。これはスタックマシンのVMの話だからまた別の話なのかもしれませんけど。
0406デフォルトの名無しさん
05/01/22 13:01:52妥協案として実行時に defineや lambdaに出食わしたら、その時の環境を使ってボディを構文解析するというのを思いつきますた。
でもそれでは
(define (my-if a b c) (let ((if if)) (if a b c)))
は解析できても
(define (my-if a b c) (if a b c))
というノーマルなやつが解析できないと思いますた。でも Gaucheでは
gosh> (define (my-if a b c) (if a b c))
my-if
gosh> (define if list)
if
gosh> (my-if #t 0 1)
0
となりました。
というか上のバージョンは実行できなかったです。scmでも実行できなくて、scheme48では定義すらできませんでした。
guileでは実行できました。
という訳で、実行時に defineや lambdaに出食わしたら rootも含めた環境でボディ部を構文解析するというのでいいのでしょうか?
それとも ifを別の名前に束縛してる場合は諦めて、ifが上書きされてないか気合いでチェックして実行前に構文解析してしまうのがいいんでしょうか?
0407デフォルトの名無しさん
05/01/22 13:06:23>一番下の環境->一個上の環境->もう一個上の環境 という風に探していくんでしょうか?
基本はその通り。
>なんか効率が悪いような。環境一つ一つはハッシュなんでしょうか?
間違いなく効率が悪い。だからインタープリターでも中間コードを使ったり、コンパイラはさらに気合いを入れた最適化をするなり。
>環境一つ一つはハッシュなんでしょうか?
トップレベルだけはハッシュを使う実装が多い。
>なんで使われなくなるのか良く分からないです
これは環境の複製を作って、オリジナルと複製の両方を使うということがないという意味で書いてみたんだけと、説明の書き方が悪かったかなりね。
>>404 secd machineでぐぐれば一発でわかると思う。
いいね〜SECDマシーン。
ちなみに、SECDによるScheme実装にはLispMeもあるなり。こっちは"SECD LispMe"でググルべし。
(LispMeという名前だけどSchemeだよん)
0408デフォルトの名無しさん
05/01/22 13:33:54(define (my-if a b c)
(let ((if if))
(if a b c)))
--> syntax errorまたはunbound variable 'if みたいなエラー
(let ((if list))
(define (my-if a b c)
(let ((if if)) (if a b c)))
(if 1 2 3))
--> (1 2 3)
これはifに束縛値があれば変数として扱い、なければsyntax keywordとして扱っているからで、構文解析するときにはトップレベルから発生しているすべての束縛を記録しておく必要があるなり。これはよくcompile time environmentと呼ばれているなり。
ちなみにgaucheで実行できるのは、
gosh> (define (my-if a b c) (if a b c))
で中間コードに変換されるときにifがsyntaxのifとして中間コードに書き込まれていて後の
gosh> (define if list) の影響を受けないから。
gosh> (define if list) (define (my-if a b c) (if a b c)) (my-if #t 0 1)
とやれば(#t 0 1)が返されるはず。
gosh> (define (my-if a b c) (let ((if if)) (if a b c)))
はやはりエラーになるんじゃないかな?
最後に、どのmy-ifの定義もifと同等の定義にはなっていないよ。これは念のためなり。
0409408
05/01/22 13:39:37(let ((if list))
(define (my-if a b c)
(let ((if if)) (if a b c)))
(if 1 2 3))
は
(let ((if list))
(define (my-if a b c)
(let ((if if)) (if a b c)))
(my-if 1 2 3))
のまちがいなり。4行も書くとバグがでるなりね(笑
0410デフォルトの名無しさん
05/01/22 13:54:59ウザイ
0411デフォルトの名無しさん
05/01/22 14:05:02えっと上のやつは
(define my-if (let ((if if)) (lambda (a b c) (if a b c))))
の間違いです。アホでした。どちみちエラーなんですけど。
>これはifに束縛値があれば変数として扱い、なければsyntax keywordとして扱っているからで、構文解析するときにはトップレベルから発生しているすべての束縛を記録しておく必要があるなり。
なるほど。記録しておく、というのは束縛が発生しているかいないかくらいでいいんでしょうか。
>これはよくcompile time environmentと呼ばれているなり。
compile time environmentですか。この言葉だけで全てが分かった気になりますた。
マクロの展開の話もこれですよね。つまりSICPみたく (analyze exp)とはできず (analyze exp compiletime-environment)
でないといけないと。
0412デフォルトの名無しさん
05/01/22 14:15:07>間違いなく効率が悪い。だからインタープリターでも中間コードを使ったり、コンパイラはさらに気合いを入れた最適化をするなり。
やっぱそうですか。それが嫌で、コピーするようにしたんですよね。どうせクロージャ作る時はマージするんだろうし、と思って。
でもコピーのコストが気になるのと set!に対応できないので >>401みたいなことを考えたんです。トップレベルだけがハッシュというのも納得できる
気がします。
>これは環境の複製を作って、オリジナルと複製の両方を使うということがないという意味で書いてみたんだけと、説明の書き方が悪かったかなりね。
単純にそういうことですか。理屈で分かっても実際にどういう風に操作をするのか想像できないので、ちょっと理解できなかったです。
たぶん、単にVMを作ったことないからだと思いますが。
0413デフォルトの名無しさん
05/01/22 14:47:21弾いちゃって良いと思うけどなあ。
混乱するだけでなんも良いことないし。
それよりSchemeは名前空間関係を整備してほしい。
0414デフォルトの名無しさん
05/01/22 15:09:12ローカル変数へのset!のことを考えると、基本的に環境はコピーできない。
ただ、set!されるローカル変数は静的に解析できるので、それだけを
ヒープアロケートしたメモリに置いて間接参照し、それ以外(参照only)の
変数はコピーしてしまう、という手法はある。ディスプレイって言ったっけ?
もう記憶があやふやだが。
0415デフォルトの名無しさん
05/01/22 16:32:19いろいろな最適化を幅広く解りやすくまとめてあるので
ttp://www.ccs.neu.edu/home/will/Twobit/ultimate.html
もお勧めだ。いざ進め地獄の果てまでも(笑
0416デフォルトの名無しさん
05/01/22 16:42:14そういう方法も研究されてるんですね。調べてみます。
みんな物知りですね、ほんと。
0417デフォルトの名無しさん
05/01/23 00:21:04また一人の男が門をくぐった…その門の名は lambda の門。
ガンガレおまいらw
0418デフォルトの名無しさん
05/01/23 00:58:210419デフォルトの名無しさん
05/01/23 23:27:34set!にも対応できるし、クロージャを作るときはトップだけをコピーすればいいし問題ないように思えるんですが
(どれをpopするか覚えとかないといけないですけど)、継続が絡むと破綻するってことはあるんでしょうか?
あと Gaucheは ifだけでなく consみたいな基本手続きも埋めこんでる様なんですが、これは時に仕様に反しないでしょうか?
(define (cons a b) (cons a b))
(cons 0 0)
は無限ループになるべきだと思うんですけど。
(define (cons a b) (cons a b))は
構文解析でcons, a, bは束縛変数だと分かるのでそれらには埋め込めないですよね
consが上書きされたら自分にアクセスされなくなるので、consに自分自身を埋めこむのはありかなと思ったんですが、
(define cons2 cons) (define cons list) とかされる可能性もあるのでやっぱ埋めこめないですね。
最適化の為に目をつぶったって感じでしょうか。
>>402 のGaucheのVMのスタック操作っていうページはかなり素晴らしいですね。
環境の扱いが検索する側にとって非効率に見えるんですけどそれでもあの速度がでるんですね。
上に書いた実装じゃ継続の実装も変わってくるだろうし、総合的に見たらどうなんですかね。
あと、実行前に構文解析するようにしても速度変わりませんでした。
lambdaとifくらいしかやってないんですけど。速くなるべきなんですかね。
0420デフォルトの名無しさん
05/01/24 00:29:06クロージャを作るときにボディを構文解析して第一引数の使われる場所に間接参照(ポインタのポインタ)を置いておく。
第二引数以下の使われる場所にもそれぞれ別の間接参照を置いておく。間接参照は評価されると参照先のものになる。
applyされるとそれぞれの間接参照がそれぞれの引数を指すようにする。set!は間接参照をいじることで実現する。
っていうのでトップレベルの変数以外のlookupが無くなる気がするんですが、どうでしょうか。
evalの扱いが微妙になるとは思うんですが。
0421デフォルトの名無しさん
05/01/24 01:32:50>lambdaとifくらいしかやってないんですけど。速くなるべきなんですかね。
式のタイプによる分岐を実行前に事前にしておくのが肝なので、
他の構文や手続きの適用、シンボル等もやらないと。
速度は一割五分ぐらいよくなるかなあ。
■ このスレッドは過去ログ倉庫に格納されています