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あたり
0357デフォルトの名無しさん
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くらいしかやってないんですけど。速くなるべきなんですかね。
式のタイプによる分岐を実行前に事前にしておくのが肝なので、
他の構文や手続きの適用、シンボル等もやらないと。
速度は一割五分ぐらいよくなるかなあ。
0422デフォルトの名無しさん
05/01/24 02:01:29そうですか。かなり地道な作業ですよね。コードの量が一気に増えるので微妙にためらってしまいます。
シンボルの構文解析って意味あるんですかねえ。SICPレベルだと全然意味ない気がします。
ところで()の評価は仕様で決まってないんでしょうか?
仕様を見る限り()は式では無いように思えるんですが、実際には()を返す処理系がたくさんあります。
0423デフォルトの名無しさん
05/01/24 02:28:41環境を辿って束縛している値を探す、正味の実行時間は変わらないけど
評価のたびごとにcondの条件判定をしている部分が省けて、
手続きの適用をするだけになって高速化するわけだから。
(condの条件判定をするよりも手続きの適用の方が速いと仮定して)
型タグの値でcase文を使って分岐してるんなら、高速化の余地は少ないと思う。
0424デフォルトの名無しさん
05/01/24 03:11:55なるほど。すでに型は分かっているから多態は必要ないんですね。
C++ならファンクタでどうにかなるかもしれません。
Cなら、グローバルもしくはスタティック変数使えばできなくもないかもしれないけど、すごく難しそう。
0425デフォルトの名無しさん
05/01/24 09:21:23>あと Gaucheは ifだけでなく consみたいな基本手続きも埋めこんでる様なんですが、これは時に仕様に反しないでしょうか?
>(define (cons a b) (cons a b))
>(cons 0 0)
>は無限ループになるべきだと思うんですけど
これは具体的にはトップレベルの定義をinternal definitionとみなしてletrecで束縛する処理系ならば無限ループになる。
本来ならそうあるべきなのであろうが、そうならないGaucheが仕様に反しているかは微妙だ。なぜならインタラクティブなトップレベルの規定が不明確だからで....
例えばGaucheでも
(let ()
(define (cons a b) (cons a b))
(cons 0 0))
とやれば当然無限ループとなる。
それじゃトップレベルもそれに合わせれば良さそうだが....
(define hoge 8)
(list hoge)
(define foo +)
(foo 8)
を単純に
(let ()
(define hoge 8)
(list hoge)
(define foo +)
(foo 8))
はできない。シンタックスエラーだからだ。
どうするR6RS???(笑
0426デフォルトの名無しさん
05/01/24 10:19:26トップレベルの規定が不明確というのは
(define a 1)
(define (b) a)
(set! a 10)
(b)
として1が返ってきてもいいということでしょうか?
0427デフォルトの名無しさん
05/01/24 10:25:32>ところで()の評価は仕様で決まってないんでしょうか?
>仕様を見る限り()は式では無いように思えるんですが、実際には()を返す処理系がたくさんあります。
()は#tや#fみたいに評価すると自分自身になるオブジェクト。括弧がついてるけどリストではない。
例えば (eq? () '()) --> #tだ
ところで、#nilとかにしないで()を使うことになってるのには何か理由があるんだろうけど...だれか知ってる?
0428デフォルトの名無しさん
05/01/24 10:38:36R5RS 的には quote が必要
4.1.3 Procedure calls
Note: In many dialects of Lisp, the empty combination, (), is a
legitimate expression. In Scheme, combinations must have at least one
subexpression, so () is not a syntactically valid expression.
0429デフォルトの名無しさん
05/01/24 10:51:06扱いも明記されていないので、結局処理系依存?
0430デフォルトの名無しさん
05/01/24 11:42:33ちょっと長くなるけど....
R5RSの5.2.2 Internal definitionsより
"Such definitions are known as internal definitions as opposed to the top level definitions described above. The variable defined by an internal definition is local to the <body>. That is, <variable> is bound rather than assigned ..."
とあるので、裏を返せばtop level definitionはassignmentsつまりset!と同じ動作だと推察できる。
これによれば、
(define a 1) (define (b) a) (set! a 10) (b)
は
(set! a 1) (set! b (lambda () a)) (set! a 10) (b)
となると考えられ、結果は10になるべきだと思う。
"本来ならそうあるべきなのであろうが"と書いたのはこれを根拠としてみた。
"不明確"と書いたのは、これだけでは次の動作の説明ができないと思ったからだ。
(define (hoge x) (if x "foo" "bar")) (hoge #t) (define if list) (hoge #t)
を先のように書き直すと、
(set! hoge (lambda (x) (if x "foo" "bar"))) (hoge #t) (set! if list) (hoge #t)
でも2つのhogeが返すのは両方とも"foo"でないといけない!
じゃあ本当のところはどうすればいいのか?
でも5.2.1 Top level definitionsにはほとんど何も書いてないし.....
いずれにしても1を返すのはまずいとは思う。
0431デフォルトの名無しさん
05/01/24 11:44:06そのまんま書いてありましたね、すいません。近くまでは見てたんですが。
R5RSで invalidなものを validとして扱えてもR5RS互換といえるから大丈夫なんでしょうね。
これを validにするメリットがあるなら知りたいですが。
>>419の一段落目と >>420についてはどうでしょうか?
0433デフォルトの名無しさん
05/01/24 11:58:24>(set! hoge (lambda (x) (if x "foo" "bar"))) (hoge #t) (set! if list) (hoge #t)
>でも2つのhogeが返すのは両方とも"foo"でないといけない!
いけないっていうのは良く分かりませんが、とりあえず ifは構文なので無理矢理納得するとしても
cons でも埋めこまれてるから納得できなかったんです。
(define (hoge x y) (cons x y)) (hoge 3 4) (define cons list) (hoge 3 4)
の結果は処理系によってまちまちです。
0434デフォルトの名無しさん
05/01/24 13:38:56ちょっと説明を整理してみた。
>(set! hoge (lambda (x) (if x "foo" "bar"))) (hoge #t) (set! if list) (hoge #t)
>いけないっていうのは良く分かりませんが
最初に、トップレベルでは(set! if list)はできない。
これはトップレベルのifが変数でないことを意味する。
次に、(define if list) (if 1 2 3) -> (1 2 3)
これは新しい変数ifを作りlistを束縛して呼び出し、結果の(1 2 3)を得ている。
では(define if list)の前に使われたifをどうするか?
そこではifは変数ではないので値を書き換える事はできない。
これが
(define (hoge x) (if x "foo" "bar")) (hoge #t) (define if list) (hoge #t)
でhogeが両方"foo"を返さなければならない理由。
>(define (hoge x y) (cons x y)) (hoge 3 4) (define cons list) (hoge 3 4)
>の結果は処理系によってまちまちです。
これは主なトップレベルの実装方法に2種類あるためで、明確な規定が無い為どっちが正しいとも間違いとも決められない現状ではしかたのないことではなかろうか。
ちなみに最初の方法は、
*すべてのシンボルが<undefined>という特別な状態に束縛されているとする。
*defineをset!として解釈する。
これは5.2.1 Top level definitionsに"Some implementations ..."と書いてある方法だ。
これによれば、次の様に解釈する
(set! hoge (lambda (x y) (cons x y))) (hoge 3 4) (set! cons list) (hoge 3 4)
結果は (3 . 4)と(3 4)
もう一つの方法は、トップレベルの式をbeginのシーケンスの様に解釈する。つまり
(begin (define (hoge x y) (cons x y)) (begin (hoge 3 4) (begin (define cons list) (begin (hoge 3 4)))))
みたいに扱う。
(注:実際のトップレベルでは(begin ...)の最初の式を評価した結果をディスプレイなりに出力する特別なbeginにする)
結果は(3 4)と(3 4)となる。
どっちにするかは好みだが、5.2.2との絡みから個人的には最初の方法に一票入れたい。
0435デフォルトの名無しさん
05/01/24 14:03:17(3 4)と(3 4)を返す処理系ってあるんでしょうか?
guile gosh scm scheme48 csi(checkin) biglooでは guileと goshが (3 . 4) (3 . 4)を返します。他は(3 . 4) (3 4)です。
(define kons cons) (define (hoge x y) (kons x y)) (hoge 3 4) (define kons list) (hoge 3 4)
にすると goshだけになります。
トップレベルの実装方法の違いというより最適化の問題の気がします。
goshは上の例でも(3 . 4)を返しますし、(set! cons 1)とできるからです(ifでもできます)。
ちなみに上の中で(set! cons 1)ができないのは scheme48だけです。
0436434
05/01/24 14:17:23ちなみに
(begin (define (hoge x y) (cons x y)) (begin (hoge 3 4) (begin (define cons list) (begin (hoge 3 4)))))
をそのまま評価すると(3 4) (3 4)となるけど、これは処理系がdefineをletrecに変換してしまうからで。
それで勘違いしてたです。中身をflattenしないbeginと思って読んでくださいませ。
0437434
05/01/24 14:35:20> (define kons cons) (define (hoge x y) (kons x y)) (hoge 3 4) (define kons list) (hoge 3 4) にすると goshだけになります。
ふむ。 たしかにその振る舞いは最適化に問題がありそうですね。
>goshは上の例でも(3 . 4)を返しますし、(set! cons 1)とできるからです(ifでもできます)。
goshで(set! if ...)ができてしまうとは.....意外だ。
0439デフォルトの名無しさん
05/01/25 01:11:30最低でも警告出すか、エラーにしてしまってもいいとさえ思える。
0440デフォルトの名無しさん
05/01/25 10:59:19オブジェクトのサイズが大きくなるから現実的ではないかもしれませんが。
構文解析後のオブジェクトはSICP風にやるなら環境を引数にとるメソッド一つがあれば十分なので、
それを関数ポインタメンバとして持つ、という感じでいいんでしょうか。
0441デフォルトの名無しさん
05/01/25 17:41:55slibを使おうとしたらslib:eval-loadが未定義だったので
まずslib.scmを修正してコメントアウトされていたslib:eval-loadを有効にし、
(use slib)
(require 'syntax-case)
しました。
しかしdefine-syntaxでsyntax-caseを使おうとすると
*** ERROR: define-syntax needs a syntax-rules form, but got (lambda(x)(syntax-case (以下略
というエラーが出て、どうもsyntax-rulesしか使えないような気がします。
UNIXでsyntax-caseを問題なく使える処理系があれば教えてください。
目的はsyntax-caseの練習です。
0442デフォルトの名無しさん
05/01/25 18:03:49に思いっきり書いてありました。ただ >>435の例のも OKなのかは良く分かりませんが。
>A program may use a top-level definition to bind any variable. It may subsequently alter
>any such binding by an assignment (see 4.1.6). These operations do not modify the behavior
>of Scheme's built-in procedures. Altering any top-level binding that has not been introduced
>by a definition has an unspecified effect on the behavior of the built-in procedures.
>>441
良く知らないけど Chikenというので使えるらしいです。
0443デフォルトの名無しさん
05/01/25 18:53:48slibのマクロ実装って、repl(もしくはload)を乗っ取らないといけない
んじゃなかったっけ。もし対話的に実行してるなら、goshのプロンプト直接
じゃなく、slibのreplを起動する必要があるはず。
そうしてるのにエラーが出たなら、gaucheのslibサポートが不完全なんだろう。
0444デフォルトの名無しさん
05/01/25 19:32:51>目的はsyntax-caseの練習です
それなら ttp://www.scheme.com/csv6.9c/ のpetite chez schemeがお勧めだ。(バイナリーで動くシステムが限られてるけど....)
なんといってもsyntax-caseの家元だからね!
0445デフォルトの名無しさん
05/01/26 18:58:02それは確かに道理なので、Petite Chez Schemeを入れてみました。
おお、syntax-caseが使える! 日本語使えないけど(Windows版)
しばらく遊んでみます。
うーん、これがどの処理系でも使えるようになればいいんだけど、
R6RSでは使えるようにしてくれたりはしないのかしら。
ところでsyntax-caseってidentifierとかのコンテクスト周りが
ややこしそうなんですよね。皆さん使いこなせるんでしょうか。
0446デフォルトの名無しさん
05/01/26 23:40:47よくわからないような、ちょっとわかったような。
(syntax-object->datum obj)
"datum"を返すらしいが、ようするにシンボルとかquoteされたS式
(テンプレートに入ってる式の字面)が入っていると考えればいいんだろうか。
(free-identifier=? obj1 obj2)
変数として束縛されていない場合のみマッチさせたい場合は
free-identifier=?を使うということでいいのかしら。
(bound-identifier=? obj1 obj2)
bound-identifier=? ってのは同じ束縛を参照してるってことなんかなあ。
これが一番よくわからない。
0447デフォルトの名無しさん
05/01/29 02:19:45http://www.schemers.org/Documents/Standards/Charter/2004-10-13.pdf
0448デフォルトの名無しさん
05/01/30 01:59:20前スレで既出。
0449万物流転
05/02/03 09:20:18(ref (sys-localtime (sys-time)) 'mon) => 1
になるのは私だけでしょうか?
0450デフォルトの名無しさん
05/02/03 09:45:40自分もなりますけど、何か問題あるっけ?
一応言っておくと、
monをrefして返る数字は0-11、つまり1が2月ですよ。
以下を参照。
http://www.shiro.dreamhost.com/scheme/gauche/man/gauche-refj_131.html
0451万物流転
05/02/03 10:45:41マニュアルをきちんと読まない私が馬鹿でした。
お騒がせしました。
0452デフォルトの名無しさん
05/02/03 11:20:10【SICP】計算機プログラムの構造と解釈【Scheme】
http://pc5.2ch.net/test/read.cgi/tech/1107345738/
ついでに、下のスレッドも紹介しておきます。
【一日】CommonLisp【一門】
http://pc5.2ch.net/test/read.cgi/tech/1106587515/
0453デフォルトの名無しさん
05/02/03 11:45:20よい経験をなさいましたな。
小生、テスターに届いたときには既に時限爆弾で期限切れとなっていたというベータ版を知っております。仕様の勘違いから1ヶ月計算がずれたわけですな。
今では懐かしい想いで..... はあと。
0454デフォルトの名無しさん
05/02/03 20:13:45Cのスタックをそのまま使って evalと applyの相互再帰で実装すると
わりと簡単にスタックオーバーフローで segmantation faultになって
しまいませんか?
やっぱスタック(もしくはCPS?)から自作しないといけないんですかねえ。
0455デフォルトの名無しさん
05/02/03 21:25:06規格上は末尾再帰でなかったらスタックをバカ食いしてもOKだと思う。
0456デフォルトの名無しさん
05/02/03 22:02:04メモリ使用量の話ではなく、スタックオーバーフローの話です。
ヒープに自作スタックを置けばメモリの許す限り使えるし、
連続した領域じゃなくてもいいかもしれないから、良いことが多いん
じゃないかと。継続も実装しやすいでしょうし。
デメリットとしてスタック積むのが遅くなったりするのかも知れませんが
どの程度か良くわからないです。
schemeでたかが5000回程度の再帰で溢れてしまうので問題かなあと思ったんですが
guileはもっと浅くても溢れてしまうので OKなんでしょうか。
SECDR(これは当たり前?)や minischemeでさえ溢れないのに。
■ このスレッドは過去ログ倉庫に格納されています