トップページ⇒tech
1001コメント355KB

CommonLisp Scheme Part12

■ このスレッドは過去ログ倉庫に格納されています
0001デフォルトの名無しさんNGNG
過去スレ
Part1: 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
>>356
今年マリノスが勝って終わったやつ。
0358デフォルトの名無しさんNGNG
東経110度でスカパーとかやってるやつ。
0359デフォルトの名無しさんNGNG
無線とかで最初にいうやつ。
0360デフォルトの名無しさんNGNG
シャア専用の略
0361355NGNG
マジレスするとComputer Scienceの略。 コンピュータ・サイエンス専攻なら英語で

I'm a CS major at ** university. で通じるよ。
0362デフォルトの名無しさんNGNG
Computer Systemかと思った。
0363デフォルトの名無しさんNGNG
>>345
> ところで自由変数を参照しない手続きを呼ぶ用語に困っているのですが、
> 何か適当な用語はあるでしょうか。

「自由変数を参照しない手続き」といえばコンビネータだけど
ちょっとニュアンスが違うような気もしないでもない?
0364デフォルトの名無しさんNGNG
「副作用があるから関数とは呼びにくい」って書いてなかったか…?
コンビネータは、普通はあまり副作用のないイメージが。

「閉じた式」(=自由変数のない式)の類推で、「閉じた手続き」じゃ駄目?
0365デフォルトの名無しさんNGNG
関数じゃないならSubとかProcedureでいいじゃん
0366デフォルトの名無しさんNGNG
凄く初歩的なことのような気がするのですが質問良いでしょうか…

(define aaa "hello, world")
(define (bbb) 'aaa)

(ccc (bbb)) => "hello, world"

になるような手続きcccってあるんでしょうか。
evalしかないですか?
0367デフォルトの名無しさんNGNG
あとはマクロぐらいじゃない?
0368デフォルトの名無しさんNGNG
quoteをつけることによって、evalしないわけだから、この場合明示的にevalしなきゃ
いけないんじゃない? sicpの4章を読みましょう。
0369366NGNG
そうですか。ありがとうございます。

とりあえずSICPも読んでみます。
0370デフォルトの名無しさんNGNG
束縛をつかうからダメなだけで、シンボルと値の対応表を別に作ってassqすればいいんでないかい?
0371344NGNG

>>353
遅くなりましたが、教えていただきありがとうございます。
これから試してみます。
0372デフォルトの名無しさんNGNG
関数で、結果が環境に依存せず引数だけで決まり、また、
副作用ももたないものを形容する言葉はありますか?
+や-などがその仲間だとおもいます。よろしくお願いします。
0373339NGNG
明けましておめでとうございます。

返事がおくれてすみません。
>>363,364
さすがにコンビネータはちょっとそぐわない気がいたします。
閉じた手続きはいいかも知れません。closed-procedureでしょうか?

>>348
そういうのは組込みの手続きを用意していてそれをコンパイラが埋め込みます。
初期化段階ではLisp/Scheme的な大域環境が(シンボルも)存在しないので。

>>372
それを関数(function)と呼ぶのではないでしょうか。
副作用があったり環境に依存するものを含めた総称がprocedureではないかと思います。
0374デフォルトの名無しさんNGNG
>>373
> それを関数(function)と呼ぶのではないでしょうか。
> 副作用があったり環境に依存するものを含めた総称がprocedureではないかと思います。
すみません、書き忘れました。Common Lispに限定しますと、規格書やコミュニティー内でも、
そのような区別はされていないようです。
(functionpなんてpredicateはそういう区別をしません。)
0375339NGNG
Common Lispの場合はそうですね。

関数が手続き一般を指す場合、"pure function" というのが使われることが
多そうな気がします。元はfortran用語でしょうか。

0376デフォルトの名無しさんNGNG
>>375 なるほど。ありがとうございました。
0377デフォルトの名無しさんNGNG
>>373
(define (hoge x y) (cons x y))
(define (cons x y) ...)
はどう処理されるの?
0378339NGNG
>>377
いまのところ、そういうことはしない、というのが答です。
というのも、フルセットの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デフォルトの名無しさんNGNG
Daniel P. Friedman: A Celebration
ttp://www.cs.indiana.edu/dfried_celebration.html
0380デフォルトの名無しさんNGNG
>>380
Schemeで著明な人達の写真が見れるね。
Guy Steeleの顔ぐらいしか知らなかった。
0381デフォルトの名無しさんNGNG
ドレッドヘアーの黒人は誰?
0382デフォルトの名無しさんNGNG
lisper が書く情報科学の wikibooks を見てみたい。
0383デフォルトの名無しさんNGNG
どなたかSECDR-Schemeの再ウプきぼんぬ。
小さくて速い処理系を探してまして、最も有望なBitとSECDR-Schemeのポインタが切れていたもので。
0384デフォルトの名無しさんNGNG
リンクは切れてたけど適当にURL推測したらあったよ>SECDR。
去年の話だけど。
0385デフォルトの名無しさんNGNG
型付きラムダ計算について書いてある資料で、
何かお勧めのやつあれば教えてください。
サイトでも教科書でも構いませんので……

MLのスレで聞いたほうがいいのかな?
0386デフォルトの名無しさんNGNG
型付きラムダ計算について書いてある資料で、
何かお勧めのやつあれば教えてください。
サイトでも教科書でも構いませんので……

MLのスレで聞いたほうがいいのかな?
0387デフォルトの名無しさんNGNG
>>386
MLの偉い人で、大堀先生の本はどうだろう。

共立出版 情報数学口座9「プログラミング言語の基礎理論」
http://www.jaist.ac.jp/~ohori/texts/index.html

この本に
形無しλ計算 → 型付きλ計算 → 多相型λ計算 → ML
の順番で説明されてたと思う。



0388デフォルトの名無しさんNGNG
>>387
その本にもあるかわかんないけど、
おれ論理式がよくわかんなかった。
でかい分数表記のやつ。
つーかあの辺理解できる気がしない。
実際どう動くかコードで示してほしかった・・・なんて無茶か。
0389デフォルトの名無しさんNGNG
>>383
ttp://paw.s2.x-beat.com/up/img/4398.zip
zipの中身がSECDR-Scheme1.0.tgz
これのオリジナルが置いてあった場所はniftyだったと思う。
0390デフォルトの名無しさんNGNG
>>387
レスどうもありがとうです.
とりあえず図書館で探して読んでみるとです.
0391383NGNG
>389
多謝。ドキュメントが詳しいのも良いっすな。
0392紫藤05/01/18 11:24:21
reply to 58:
> Paul Graham, ANSI Common Lisp の練習問題の解答を載せた
>ホームページ等、ご存知でしたら教えていただけませんでしょうか

http://www.geocities.jp/shido_takafumi/pacl2.html
に書いたのでよろしかったら見てください。
せっかく書いたのに誰も見てくれないので宣伝します。
0393デフォルトの名無しさん05/01/20 22:58:06
習作のSchemeもどきの実装を晒しても良いですか?
0394デフォルトの名無しさん05/01/20 23:01:13
>>393
おねがいします。
0395デフォルトの名無しさん05/01/20 23:05:12
初めて作った実装なのでダメダメかもしれません。
とりあえず mini-schemeよりは速いはずです。
継続がなくて、マクロもどきや環境がファーストクラスです。
中間コードにコンパイルする方法を勉強して継続を実装したりしたいです。
http://primes.dnip.net/scheme.cpp
0396デフォルトの名無しさん05/01/21 10:40:10
>>395
たらい回ししてみようか…と思ったら、比較オペレータは定義されてなかった。
まだまだテスト版だからってことでしょうか。

ちょっと見てみると、scheme_oprtクラスとか無駄してるような…。
C++で実装するというのは、C使いの自分には面白かったです。がんばってください。

これだけのコードでまがりなりにも
処理系を作れてしまうというのが、Scheme(lisp)の良さですよね。
0397デフォルトの名無しさん05/01/21 11:44:13
>>396
比較オペレータなどを定義してみました。
scheme_oprtクラスは無駄してるでしょうか? よく分かんないです。
整数や真偽値や基本手続きをポインタではなく即値で埋めこむテクニックを知ったのですが
この先中間コードにコンパイルすることを考えると、今はどっちでもいいのかなあと思いました。

中間コードの話はSICP5章とドラゴンブック以外に参考になる文献はあるでしょうか?
特に継続の実装がさっぱり分からないです。
039839605/01/21 14:45:19
>>397
わっ、反応早い!

scheme_oprtクラスのprintメソッドは、簡単なやり方でも、
とりあえず先にprintf("#<subr ")しておいて、if文でプロシージャ名をprintfして、
最後に">"をprintfしておいた方が、無駄な文字列データが減るはずです。

aplyメソッドも、プロシージャごとに完全なコード書かずに、汎用化するとか。

色んな意味でRHG(Ruby Hacking Guide)とGHG(Gauche Hacking Guide)は
役に立つと思いますが、すでに見ているか。
0399デフォルトの名無しさん05/01/21 16:07:14
>>398
printメソッドの話ですか。そこらへんは適当です。
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
>>400
>クロージャーの呼び出しでは引数を束縛して新しい環境を作るけど、これはコピーとはちょと違うし、名前の置き換えというのも何を意味しているのかちょとわからないなり。
環境を壊したくないので、クロージャーを呼び出した時点での環境をコピーしてそれに引数の束縛を足して使うという意味です。
新しい環境を作るのにコピーはしないんでしょうか? 名前の置き変えは、環境は一つだけでかぶる引数の名前を全部置き変えるということです。

環境をリストで表現して先頭から新しい束縛を足して、検索するときは先頭から順番に調べるようにすれば、一つのポインタのコピーだけで済んで良いかなあと思いました。
ハッシュと違って検索に束縛の数に比例して時間がかかるのが欠点ですがどんなもんでしょうか。

>SRFI-17のほうは例えば(define x "hogehoge") (set! (string-ref x 4) 3.14)みたいなことはエラーになるべきだから考えなくていいんじゃないかな。
なんか勘違いしてました。ポインタの指す先を変更しないといけないのかと思ってました。
0402デフォルトの名無しさん05/01/22 11:15:08
>>401
>環境を壊したくないので、クロージャーを呼び出した時点での環境をコピーしてそれに引数の束縛を足して使うという意味です
ふむふむそういうことだったか....
最初に、クロージャーの呼び出し時にはその意味での環境のコピーはないなり。すでに存在する環境に引数から作った環境をリンクするだけなり。
次に、lambdaでクロージャーを作るときは環境をスタックからヒープに移動することはあるけれど、元のスタック上の環境は以後は使われなくなるなり。
>新しい環境を作るのにコピーはしないんでしょうか?
引数から新しい環境を作ったら以前の環境に対してリンクを張るだけなり。

このへんは >>3 の"Practical Scheme"が詳しい。
特に実装についてはその中の以下のページが素晴らしいなり。
ttp://www.shiro.dreamhost.com/scheme/stack-j.html
ttp://www.shiro.dreamhost.com/scheme/gauche/memo-stack-j.html
040340205/01/22 11:37:42
>すでに存在する環境に引数から作った環境をリンクする
「すでに存在する環境」はクロージャーの持っている環境のことなり。
>元のスタック上の環境は以後は使われなくなるなり
これは完全にゴミになるということなり(実際デバッグ時には"0xcafecafe"とかで破壊するとよい)

どうもShiroのようにはうまく説明できないのう。
0404デフォルトの名無しさん05/01/22 12:00:50
secd machineでぐぐれば一発でわかると思う。
0405デフォルトの名無しさん05/01/22 12:36:55
>>402
なるほど。ちょっと難しいですが、20%くらい分かった気がします。
名前を検索するときは envポインタからたどって、
一番下の環境->一個上の環境->もう一個上の環境 という風に探していくんでしょうか?
なんか効率が悪いような。環境一つ一つはハッシュなんでしょうか?

>次に、lambdaでクロージャーを作るときは環境をスタックからヒープに移動することはあるけれど、元のスタック上の環境は以後は使われなくなるなり。
なんで使われなくなるのか良く分からないです。これはスタックマシンのVMの話だからまた別の話なのかもしれませんけど。
0406デフォルトの名無しさん05/01/22 13:01:52
SICP 4.1.7にあるような構文解析をしようと思ったんですが、quoteや ifに別の値が束縛されていると困ることに気づきました。
妥協案として実行時に 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
>>405
>一番下の環境->一個上の環境->もう一個上の環境 という風に探していくんでしょうか?
基本はその通り。
>なんか効率が悪いような。環境一つ一つはハッシュなんでしょうか?
間違いなく効率が悪い。だからインタープリターでも中間コードを使ったり、コンパイラはさらに気合いを入れた最適化をするなり。
>環境一つ一つはハッシュなんでしょうか?
トップレベルだけはハッシュを使う実装が多い。
>なんで使われなくなるのか良く分からないです
これは環境の複製を作って、オリジナルと複製の両方を使うということがないという意味で書いてみたんだけと、説明の書き方が悪かったかなりね。

>>404 secd machineでぐぐれば一発でわかると思う。
いいね〜SECDマシーン。

ちなみに、SECDによるScheme実装にはLispMeもあるなり。こっちは"SECD LispMe"でググルべし。
(LispMeという名前だけどSchemeだよん)
0408デフォルトの名無しさん05/01/22 13:33:54
>>406
(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と同等の定義にはなっていないよ。これは念のためなり。
040940805/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
>>408
えっと上のやつは
(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
>>407
>間違いなく効率が悪い。だからインタープリターでも中間コードを使ったり、コンパイラはさらに気合いを入れた最適化をするなり。
やっぱそうですか。それが嫌で、コピーするようにしたんですよね。どうせクロージャ作る時はマージするんだろうし、と思って。
でもコピーのコストが気になるのと set!に対応できないので >>401みたいなことを考えたんです。トップレベルだけがハッシュというのも納得できる
気がします。

>これは環境の複製を作って、オリジナルと複製の両方を使うということがないという意味で書いてみたんだけと、説明の書き方が悪かったかなりね。
単純にそういうことですか。理屈で分かっても実際にどういう風に操作をするのか想像できないので、ちょっと理解できなかったです。
たぶん、単にVMを作ったことないからだと思いますが。
0413デフォルトの名無しさん05/01/22 14:47:21
おれはマクロや構文のキーワードの参照したらエラーとして
弾いちゃって良いと思うけどなあ。
混乱するだけでなんも良いことないし。
それよりSchemeは名前空間関係を整備してほしい。
0414デフォルトの名無しさん05/01/22 15:09:12
>>412
ローカル変数へのset!のことを考えると、基本的に環境はコピーできない。
ただ、set!されるローカル変数は静的に解析できるので、それだけを
ヒープアロケートしたメモリに置いて間接参照し、それ以外(参照only)の
変数はコピーしてしまう、という手法はある。ディスプレイって言ったっけ?
もう記憶があやふやだが。
0415デフォルトの名無しさん05/01/22 16:32:19
>>414 のいってるやつは"orbit compiler scheme"でググればタダで論文が読めるぞ。
いろいろな最適化を幅広く解りやすくまとめてあるので
ttp://www.ccs.neu.edu/home/will/Twobit/ultimate.html
もお勧めだ。いざ進め地獄の果てまでも(笑
0416デフォルトの名無しさん05/01/22 16:42:14
>>414 >>415
そういう方法も研究されてるんですね。調べてみます。
みんな物知りですね、ほんと。
0417デフォルトの名無しさん05/01/23 00:21:04
>>415
また一人の男が門をくぐった…その門の名は lambda の門。
ガンガレおまいらw
0418デフォルトの名無しさん05/01/23 00:58:21
俺も今schemeのインタプリタ作ってるので非常に参考になります…。
0419デフォルトの名無しさん05/01/23 23:27:34
シンボルから引けるオブジェクトをスタック構造にするというのは問題あるでしょうか?
set!にも対応できるし、クロージャを作るときはトップだけをコピーすればいいし問題ないように思えるんですが
(どれを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
lambdaの最適化について妄想ですが、
クロージャを作るときにボディを構文解析して第一引数の使われる場所に間接参照(ポインタのポインタ)を置いておく。
第二引数以下の使われる場所にもそれぞれ別の間接参照を置いておく。間接参照は評価されると参照先のものになる。
applyされるとそれぞれの間接参照がそれぞれの引数を指すようにする。set!は間接参照をいじることで実現する。
っていうのでトップレベルの変数以外のlookupが無くなる気がするんですが、どうでしょうか。
evalの扱いが微妙になるとは思うんですが。
0421デフォルトの名無しさん05/01/24 01:32:50
>あと、実行前に構文解析するようにしても速度変わりませんでした。
>lambdaとifくらいしかやってないんですけど。速くなるべきなんですかね。
式のタイプによる分岐を実行前に事前にしておくのが肝なので、
他の構文や手続きの適用、シンボル等もやらないと。
速度は一割五分ぐらいよくなるかなあ。
0422デフォルトの名無しさん05/01/24 02:01:29
>>421
そうですか。かなり地道な作業ですよね。コードの量が一気に増えるので微妙にためらってしまいます。
シンボルの構文解析って意味あるんですかねえ。SICPレベルだと全然意味ない気がします。

ところで()の評価は仕様で決まってないんでしょうか?
仕様を見る限り()は式では無いように思えるんですが、実際には()を返す処理系がたくさんあります。
0423デフォルトの名無しさん05/01/24 02:28:41
SICPのような実装だと意味がある。
環境を辿って束縛している値を探す、正味の実行時間は変わらないけど
評価のたびごとにcondの条件判定をしている部分が省けて、
手続きの適用をするだけになって高速化するわけだから。
(condの条件判定をするよりも手続きの適用の方が速いと仮定して)

型タグの値でcase文を使って分岐してるんなら、高速化の余地は少ないと思う。
0424デフォルトの名無しさん05/01/24 03:11:55
>>423
なるほど。すでに型は分かっているから多態は必要ないんですね。
C++ならファンクタでどうにかなるかもしれません。
Cなら、グローバルもしくはスタティック変数使えばできなくもないかもしれないけど、すごく難しそう。
0425デフォルトの名無しさん05/01/24 09:21:23
>>419
>あと 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
>>425
トップレベルの規定が不明確というのは
(define a 1)
(define (b) a)
(set! a 10)
(b)
として1が返ってきてもいいということでしょうか?
0427デフォルトの名無しさん05/01/24 10:25:32
>>422
>ところで()の評価は仕様で決まってないんでしょうか?
>仕様を見る限り()は式では無いように思えるんですが、実際には()を返す処理系がたくさんあります。
()は#tや#fみたいに評価すると自分自身になるオブジェクト。括弧がついてるけどリストではない。

例えば (eq? () '()) --> #tだ

ところで、#nilとかにしないで()を使うことになってるのには何か理由があるんだろうけど...だれか知ってる?
0428デフォルトの名無しさん05/01/24 10:38:36
>>427
R5RS 的には 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
not valid ではあるけど、invalid とされているわけでもなく
扱いも明記されていないので、結局処理系依存?
0430デフォルトの名無しさん05/01/24 11:42:33
>>427
ちょっと長くなるけど....
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
>>428
そのまんま書いてありましたね、すいません。近くまでは見てたんですが。
R5RSで invalidなものを validとして扱えてもR5RS互換といえるから大丈夫なんでしょうね。
これを validにするメリットがあるなら知りたいですが。

>>419の一段落目と >>420についてはどうでしょうか?
043242705/01/24 11:50:28
>>428
ほんとだ、しかも(list? '()) -> #t だし。
マリアナ海溝より深く反省します m(_ _)m
0433デフォルトの名無しさん05/01/24 11:58:24
>>430
>(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
>>433
ちょっと説明を整理してみた。
>(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
>>434
(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だけです。
043643405/01/24 14:17:23
ごめんなさい。最初のやつの結果が(3 . 4)(3 . 4)次のやつの結果が(3 . 4)(3 4)でした(滝汗
ちなみに
(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と思って読んでくださいませ。
043743405/01/24 14:35:20
>>435
> (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 ...)ができてしまうとは.....意外だ。
043843405/01/24 14:43:56
>>434
ああ、また間違えてる。最初が(3 . 4) (3 4)、次が(3 . 4)(3 . 4)。まったく俺って情けない(涙
0439デフォルトの名無しさん05/01/25 01:11:30
構文やマクロキーワードは処理系開発側からするといじらんでほしい。
最低でも警告出すか、エラーにしてしまってもいいとさえ思える。
0440デフォルトの名無しさん05/01/25 10:59:19
ちょっと思ったんですが、型タグを使うよりも直接関数ポインタをメンバに持てばswitchを省けますよね。
オブジェクトのサイズが大きくなるから現実的ではないかもしれませんが。
構文解析後のオブジェクトはSICP風にやるなら環境を引数にとるメソッド一つがあれば十分なので、
それを関数ポインタメンバとして持つ、という感じでいいんでしょうか。
0441デフォルトの名無しさん05/01/25 17:41:55
Gaucheでsyntax-caseは使えるのでしょうか?
slibを使おうとしたら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
お騒がせしてしまってすみませんが、標準手続きへの割り当ての問題は R5RSの Chapter6の最初
に思いっきり書いてありました。ただ >>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:48
>>441
slibのマクロ実装って、repl(もしくはload)を乗っ取らないといけない
んじゃなかったっけ。もし対話的に実行してるなら、goshのプロンプト直接
じゃなく、slibのreplを起動する必要があるはず。
そうしてるのにエラーが出たなら、gaucheのslibサポートが不完全なんだろう。

0444デフォルトの名無しさん05/01/25 19:32:51
>>441
>目的はsyntax-caseの練習です
それなら ttp://www.scheme.com/csv6.9c/ のpetite chez schemeがお勧めだ。(バイナリーで動くシステムが限られてるけど....)
なんといってもsyntax-caseの家元だからね!
0445デフォルトの名無しさん05/01/26 18:58:02
>>444
それは確かに道理なので、Petite Chez Schemeを入れてみました。
おお、syntax-caseが使える! 日本語使えないけど(Windows版)
しばらく遊んでみます。
うーん、これがどの処理系でも使えるようになればいいんだけど、
R6RSでは使えるようにしてくれたりはしないのかしら。

ところでsyntax-caseってidentifierとかのコンテクスト周りが
ややこしそうなんですよね。皆さん使いこなせるんでしょうか。

0446デフォルトの名無しさん05/01/26 23:40:47
syntax-caseで使うfree-identifier=?とかbound-identifier=?とかがいまひとつ
よくわからないような、ちょっとわかったような。

(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:45
R6RSの検討ってしてるのね。
http://www.schemers.org/Documents/Standards/Charter/2004-10-13.pdf
0448デフォルトの名無しさん05/01/30 01:59:20
>>447
前スレで既出。
0449万物流転05/02/03 09:20:18
Gaucheで
(ref (sys-localtime (sys-time)) 'mon) => 1
になるのは私だけでしょうか?
0450デフォルトの名無しさん05/02/03 09:45:40
>>449
自分もなりますけど、何か問題あるっけ?

一応言っておくと、
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
≫450
マニュアルをきちんと読まない私が馬鹿でした。
お騒がせしました。
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
>>451
よい経験をなさいましたな。
小生、テスターに届いたときには既に時限爆弾で期限切れとなっていたというベータ版を知っております。仕様の勘違いから1ヶ月計算がずれたわけですな。
今では懐かしい想いで..... はあと。
0454デフォルトの名無しさん05/02/03 20:13:45
schemeで末尾再帰でない再帰関数を書くことがあると思うんですが、
Cのスタックをそのまま使って evalと applyの相互再帰で実装すると
わりと簡単にスタックオーバーフローで segmantation faultになって
しまいませんか?
やっぱスタック(もしくはCPS?)から自作しないといけないんですかねえ。
0455デフォルトの名無しさん05/02/03 21:25:06
減らしたほうがいいのは確かだが、
規格上は末尾再帰でなかったらスタックをバカ食いしてもOKだと思う。
0456デフォルトの名無しさん05/02/03 22:02:04
>>455
メモリ使用量の話ではなく、スタックオーバーフローの話です。
ヒープに自作スタックを置けばメモリの許す限り使えるし、
連続した領域じゃなくてもいいかもしれないから、良いことが多いん
じゃないかと。継続も実装しやすいでしょうし。
デメリットとしてスタック積むのが遅くなったりするのかも知れませんが
どの程度か良くわからないです。

schemeでたかが5000回程度の再帰で溢れてしまうので問題かなあと思ったんですが
guileはもっと浅くても溢れてしまうので OKなんでしょうか。
SECDR(これは当たり前?)や minischemeでさえ溢れないのに。
■ このスレッドは過去ログ倉庫に格納されています