1 名前:デフォルトの名無しさん mailto:sage [04/08/02 23:13] 過去スレ Part1: piza2.2ch.net/tech/kako/987/987169286.html Part2: pc.2ch.net/tech/kako/1002/10025/1002584344.html Part3: pc.2ch.net/tech/kako/1008/10082/1008220265.html Part4: pc.2ch.net/tech/kako/1016/10162/1016211619.html Part5: pc3.2ch.net/tech/kako/1023/10230/1023091882.html Part6: pc3.2ch.net/tech/kako/1031/10315/1031560687.html Part7: ruku.qp.tc/dat2ch/0311/20/1042167213.html Part8: pc2.2ch.net/tech/kako/1058/10582/1058263391.html Part9: pc2.2ch.net/test/read.cgi/tech/1069594582/ Part10: pc5.2ch.net/test/read.cgi/tech/1075630259/ 関連リンクは>>2-10 あたり
710 名前:デフォルトの名無しさん mailto:sage [04/10/11 18:58:09] a.soのシンボルをリストアップしてみりゃわかるよ
711 名前:708 mailto:sage [04/10/11 19:20:52] >>710 はじめてナノメートル nm しました. うまくいきました! ありがとうございます. 今から >>710 に萌えます (;´Д`) gcc で作ったやつと比較して,トンでもないシンボル名になっていました. でもその名前で lisp コードに書き,アンダーバー `_' をハイフン `-' に変えて 使ってみると,正常に動きました. シンボル名が変にならないようにする方法はこれから調べます.
712 名前:デフォルトの名無しさん mailto:sage [04/10/11 19:35:31] >>705 see srfi-56
713 名前:デフォルトの名無しさん [04/10/11 22:27:42] call-with-current-continuationについて教えてください. 多分誤解しているのだと思います. たとえば, (call/cc (lambda (k) (* 20 (k 30)))) => 30 になると思います. これを, 「kというprocedureがactiveになった時点で,それに 渡されるべき30という引数が返されたのである」と 理解していましたが,これは誤りなのでしょうか? この考え方をもって既存のコードを読むと,実際に 返される値と異なる結果になってしまいます. どこがいけないか,ご指摘願えますでしょうか. よろしくお願いいたします.
714 名前:デフォルトの名無しさん mailto:sage [04/10/11 22:55:04] kという手続きがxを引数に呼び出されると、 対応するcall/ccの返却値としてxが戻される。 もちろん後続の処理もcall/ccが普通に戻った場合と同じように続く。
715 名前:デフォルトの名無しさん mailto:sage [04/10/11 23:08:44] >>713 「procedureがactiveになる」ってどゆこと?
716 名前:デフォルトの名無しさん mailto:sage [04/10/11 23:24:50] >>713 Gaucheでの出力だけど... (define m '()) (list 1 2 3 (call/cc (lambda (k) (set! m k))) 4 5 6) --> (1 2 3 #<subr continuation> 4 5 6) m -->#<subr continuation> (m 999) --> (1 2 3 999 4 5 6) (list 1 2 3 (+ 100 (call/cc (lambda (k) (set! m k)))) 4 5 6) --> 継続と100は足せないというエラー (list 1 2 3 (+ 100 (call/cc (lambda (k) (set! m k) 100))) 4 5 6) --> 1 2 3 200 4 5 6 (m 500) -->1 2 3 600 4 5 6 つまり継続を呼び出すときの引数でそれを作った(call/cc ...)が丸ごと置き換わると考えるととりあえずよいかもしれない。 うまい説明になってないかな^^? (list 1 2 3 (+ 100 (call/cc (lambda (k) (set! m k)))) 4 5 6) --> 継続と100は足せないというエラー (list 1 2 3 (+ 100 (call/cc (lambda (k) (set! m k) 100))) 4 5 6) --> 1 2 3 200 4 5 6 (m 500) -->1 2 3 600 4 5 6 つまり継続を呼び出すときの引数で(call/cc ...)が丸ごと置き換わると考えるととりあえずよいかもしれない。 あまり説明になってないかな^^?
717 名前:デフォルトの名無しさん [04/10/11 23:26:16] >> 715 713です. 「procedureが呼び出される」に訂正. >> 714 ありがとうございます. ということは根本的に間違えた考えではないと理解して, コードを追い直しています.
718 名前:716 mailto:sage [04/10/11 23:27:55] 書き込みの途中に継続を呼んでしまったようだ... ごめん m(_ _)m
719 名前:デフォルトの名無しさん [04/10/11 23:45:56] >> 716 ありがとうございます. 実際に追っているコードを示した方が早いので,そうします. たとえば,Kent Dybvig プログラミング言語Scheme (日本語版) p.61に,call/ccのサンプルとして (let ((x (call/cc (lambda (k) k)))) (x (lambda (ignore) "hi"))) => "hi" というのがありますが,これは結局 (call/cc (lambda (k) k) (lambda (ignore) "hi")) と等価(でよいのでしょうか)ですね. この式内の引数 (lambda (ignore) "hi")はprocedure だから,答は本にあるように "hi" じゃなくて,その procedure自体(#<user-defined-function> みたい) になると思うのです. しかし確かにguileなどでは本の通り "hi" と出ます. 問題はこのprocedure自体を返すのか,evalった結果を 返すのかの違いにあるのだと思いますが、「eval忘れ」 がどこかにあるのでしょうか? ちなみに kawa ではエラーとなり確認できません.
720 名前:デフォルトの名無しさん mailto:sage [04/10/11 23:47:02] >>711 >シンボル名が変にならないようにする方法はこれから調べます. そいつはC++を使ってる限り無理だ。関数の多重定義を実現するために、 シンボルには型情報がくっつくようになってる。
721 名前:デフォルトの名無しさん mailto:sage [04/10/11 23:47:17] 継続(continuation)のメモ ttp://www.opengroupware.jp/~hoti/blog/Scheme
722 名前:デフォルトの名無しさん [04/10/12 00:03:24] 719 です. >問題はこのprocedure自体を返すのか,evalった結果を >返すのかの違いにあるのだと思いますが、「eval忘れ」 >がどこかにあるのでしょうか? は間違いですね。 問題はこのprocedure自体を返すのか,呼び出した結果を 返すのかの違いにあるのだと思いますが、「呼び出し忘れ」 がどこかにあるのでしょうか? の意味です。
723 名前:708 mailto:sage [04/10/12 00:04:17] >>720 なんと,,,そうですか.今ちょっと調べ疲れていたところでした. どうもありがとうございました. まあ lisp コードなんてすぐ修正できてしまうからいいんですよね!
724 名前:デフォルトの名無しさん mailto:sage [04/10/12 00:13:42] >>719 最初に (x (lambda (ignore) "hi")) を評価するとき x は継続であり、それは 「最初の (call/cc (lambda (k) k))」から戻ってきて、返却値を x に bind し、let の body を評価する」 という継続である。 なので、これを評価すると最初の (call/cc (lambda (k) k)) から (lambda (ignore) "hi") が返却され、 これが x に bind され、(x (lambda (ignore) "hi")) が再度評価されることになる。 二度目に評価されるとき、x には (lambda (ignore) "hi") が bind されているので、これはつまり ((lambda (ignore) "hi") (lambda (ignore) "hi")) ということになり、最終的に "hi" が返却される。
725 名前:デフォルトの名無しさん [04/10/12 00:34:47] 訂正 719の中の置換したコードは ((call/cc (lambda (k) k)) (lambda (ignore) "hi")) のつもりでした. >>724 ありがとうございます.最終的に ((lambda (ignore) "hi") (lambda (ignore) "hi")) に置換されるのがミソのようですね. まだまだSchemerになれていないので,724をなぞって ゆっくり考えます.ありがとうございました.
726 名前:デフォルトの名無しさん mailto:sage [04/10/12 01:59:29] >>723 extern "C" { ネコミミモード };
727 名前:716 mailto:sage [04/10/12 02:43:54] おれが安易に「丸ごと置き換わると考えるととりあえずよいかもしれない」なんて書いちゃったのは良くなかった。ごめんなさい m(_ _)m 置換で考えると上手くない場合もあるんだ。 例えば、 (let ((c 100)) (let ((x (call/cc (lambda (k) k)))) ;<- @1 (let ((c 200)) (x (lambda (n) (+ 1 c)))))) ;<- @2 --> 201 の (call/cc (lambda (k) k)) を単純に (lambda (n) (+ 1 c))に置き換えて考えてしまうと (let ((c 100)) (let ((x (lambda (n) (+ 1 c)))) (let ((c 200)) (x (lambda (n) (+ 1 c)))))) --> 101 となって結果が合わなくなってしまう。 これは@2のlambdaで作られた#<closure>は@1に送られるけど、その環境は@2を持っているということが単純な置換で考えると消えてしまうからなんだ。 というわけで、716は忘れてください ^^;
728 名前:デフォルトの名無しさん mailto:sage [04/10/12 09:57:42] スコープだけじゃないね。 (let ((x 0)) (let ((c (call/cc (lambda (x) x)))) (set! x (+ x 1)) (c (lambda (y) x)))) と (let ((x 0)) (let ((c (lambda (y) x))) (set! x (+ x 1)) (c (lambda (y) x)))) はちがうし。 あたかも置き換えたかのようにジャンプするというか・・・。
729 名前:デフォルトの名無しさん [04/10/12 20:10:09] 713です. 多くの丁寧な follow-up をありがとうございます. call/ccはSchemeらしいところだと思うのですが それだけ奥が深いですね. 何せ midnight programmer なものですから, これから寝るまで頭をひねって考えます. 今後ともよろしくお願いします.
730 名前:デフォルトの名無しさん mailto:sage [04/10/12 20:27:57] schemeの継続って、プログラムの最小限要素をくくりだすのはいいが そのためにやたらコストの高いものを導入してしまったという感じがする。 Smalltalkでの何でもかんでもオブジェクトとメッセージに近いものがある。 継続そのものが便利なときもあるけど、なくてもほとんど困らない。
731 名前:デフォルトの名無しさん mailto:sage [04/10/12 20:31:45] 継続抽出は銀の弾丸です
732 名前:デフォルトの名無しさん mailto:sage [04/10/12 20:44:17] ほんとにそうなら継続のある言語がとっくに天下をとってると思う。
733 名前:デフォルトの名無しさん mailto:sage [04/10/12 21:44:11] 悪い方が良い法則。
734 名前:デフォルトの名無しさん mailto:sage [04/10/12 22:35:38] おまえらただ継続継続いいたいだけちゃうんかと。 継続なんて極力使わない方がいい。 gotoがよりパワフルにそしてわかりにくくなったものだから。 銀の弾丸どころかソフトウェアエンジニアリング的には狼男だ。
735 名前:デフォルトの名無しさん mailto:sage [04/10/12 22:39:36] 例外処理のような上手い使い方ならいいんだけどね
736 名前:デフォルトの名無しさん mailto:sage [04/10/12 23:02:34] ちんちんかゆいーー!
737 名前:デフォルトの名無しさん mailto:sage [04/10/12 23:03:46] gotoが悪ならthreadなんて巨悪だな
738 名前:デフォルトの名無しさん mailto:sage [04/10/12 23:04:48] >>736 cut しろ
739 名前:デフォルトの名無しさん mailto:sage [04/10/12 23:35:23] >>737 threadとgotoは比べるもんじゃないだろ。 threadは基本的に代えがきかない。
740 名前:デフォルトの名無しさん mailto:sage [04/10/13 03:12:19] The Seasoned Schemerの継続の説明らしい章を読んでます。 で、質問なんですが、この本の中では継続を「call/cc」じゃなくて 「letcc」(schemeの場合)、「throw」「catch」(CommonLispの場合)で 説明してるんですけど、これらは等価なものなんですか?
741 名前:デフォルトの名無しさん mailto:sage [04/10/13 03:30:06] >>740 shiroさんのなぜ Scheme には return がないのか www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?Scheme%3a%a4%ca%a4%bcScheme%a4%cb%a4%cfreturn%a4%ac%cc%b5%a4%a4%a4%ce%a4%ab を読むとその辺がわかるかも。
742 名前:デフォルトの名無しさん mailto:sage [04/10/13 10:25:44] continuationとgotoは比べるもんじゃないだろ。 continuationは基本的に代えがきかない。
743 名前:デフォルトの名無しさん mailto:sage [04/10/13 14:30:21] はっきり言って、continuation≒gotoだよ。認めたくないだろうけどね。 gotoでcontinueもbreakもreturnも出来るじゃん、美しい!って悦に入ってるのが schemer
744 名前:デフォルトの名無しさん mailto:sage [04/10/13 16:12:52] だがそれがいい
745 名前:デフォルトの名無しさん mailto:sage [04/10/13 16:21:01] >>742 おうむ返しだけだと馬鹿にしか見えませんよ。 continuationはやろうと思えばいくらでも書き換えられる。 書き換えたらフラグだらけになったり、 巨大な関数になったりしてして醜いから、使う、というものでしょ。 もちろんそういうときに使うのはいいけど、 できるときはwhileとかforとかmacroにしたほうがいいだろう。 threadはthreadを使わずに同じ機能を実現することが難しい。 特にthreadのどれか一つが死んだりしても他のthreadが監視しておいて 処理できる、という能力はエミュレートできない。 エミュレートだとスケジューリングがうまくいくように一単位の 処理時間をコントロールできないといけないし。
746 名前:デフォルトの名無しさん mailto:sage [04/10/13 21:25:49] ケイゾクに恨みでもあるんですか?
747 名前:デフォルトの名無しさん mailto:sage [04/10/13 21:57:42] 色んな意味でコストがかかるところ。
748 名前:デフォルトの名無しさん mailto:sage [04/10/13 22:54:32] >>746 ないけど?
749 名前:デフォルトの名無しさん mailto:sage [04/10/14 00:13:10] threadだって高速に処理切り替えてるだけだから、 gotoで出来ないことはない。
750 名前:デフォルトの名無しさん mailto:sage [04/10/14 00:39:00] スレッドと継続は全く別個の独立した概念であり、対立するものでもないのに何をムキになってるんだろう。 > 書き換えたらフラグだらけになったり、 > 巨大な関数になったりしてして醜いから、使う、というものでしょ それこそ継続という概念が primitive なものであるということであり、scheme らしいところでは? primitive なものさえあれば他の機能はそれらを組み合わせてできる。美しい。 例えば、コルーチン程度であれば call/cc で簡単に実現できる。
751 名前:デフォルトの名無しさん mailto:sage [04/10/14 00:54:20] コルーチン程度しかできない、の間違いでしょ
752 名前:デフォルトの名無しさん mailto:sage [04/10/14 01:06:04] Rubyの継続の実装はスレッドと同じだそうですよ i.loveruby.net/ja/rhg/cd/continuation.html
753 名前:デフォルトの名無しさん mailto:sage [04/10/14 01:44:06] >>749 gotoでどうやって > 特にthreadのどれか一つが死んだりしても他のthreadが監視しておいて > 処理できる、という能力はエミュレートできない。 するんだ? そしてどうやって一つの処理単位がCPUタイムを食いすぎないことを保証するんだ? > エミュレートだとスケジューリングがうまくいくように一単位の > 処理時間をコントロールできないといけないし。 >>750 > スレッドと継続は全く別個の独立した概念であり、対立するものでもないのに何をムキになってるんだろう。 じゃああなたが>>737 や>>749 を説得して上げてください。
754 名前:デフォルトの名無しさん mailto:sage [04/10/14 01:45:11] gotoさえ使えば、breakもcontinueもreturnもいらないのはもちろん、 スレッドも関数もいもいらない。こういう機能はgotoを組み合わせてできる。 美しい。
755 名前:デフォルトの名無しさん mailto:sage [04/10/14 01:53:27] >>750 美しかろうがどうだろうが、 「継続を無闇に使うべきでない」という事実には変わりはないな。
756 名前:デフォルトの名無しさん mailto:sage [04/10/14 01:54:45] アセンブラにすりゃただのジャンプ命令。 ジャンプ命令使わずにアセンブラでプログラム組めるわけが無い。 即ち、息をするようにgotoを使え。
757 名前:デフォルトの名無しさん mailto:sage [04/10/14 04:40:12] 引数つきgoto
758 名前:デフォルトの名無しさん mailto:sage [04/10/14 08:16:21] 〉〉753OSやリアルタイム制御の本みれば書いてあるよ。つーか知らないの?
759 名前:デフォルトの名無しさん mailto:sage [04/10/14 08:28:20] ヘタレLisperと本物のプログラマを隔てるOSという一つの壁
760 名前:デフォルトの名無しさん mailto:sage [04/10/14 08:29:07] >>736-738 Prologの話?
761 名前:デフォルトの名無しさん mailto:sage [04/10/14 09:24:37] まだちんちんかゆいよーー! なぜか皮が膨らんできてる・・・
762 名前:デフォルトの名無しさん mailto:sage [04/10/14 11:39:34] >>751 ユーザモードのスレッドは、本質的にはコルーチンと同等だけど?
763 名前:デフォルトの名無しさん mailto:sage [04/10/14 16:06:08] コルーチンって何?
764 名前:デフォルトの名無しさん mailto:sage [04/10/14 16:18:27] >>763 www.google.com/search?hl=ja&lr=lang_ja&ie=SJIS&oe=SJIS&num=100&q=%83R%83%8B%81%5B%83%60%83%93
765 名前:デフォルトの名無しさん mailto:sage [04/10/14 17:26:42] >>762 ユーザーモードのスレッドは必ずしもそうでないと思うけど、 ユーザーモードのスレッドライブラリはそうだね。で、それが何か? 話は変わって、 そもそもSchemeの継続ってプリミティブか? 単にCPSで書けばいいだけじゃないの?こっちはどんな関数型言語にもできるし。
766 名前:デフォルトの名無しさん mailto:sage [04/10/14 17:43:15] 機械語のライブラリを実行中に継続を取ってきても きちんと動くように要請してるんじゃない?
767 名前:デフォルトの名無しさん mailto:sage [04/10/14 20:38:44] >>765 なんでそこに CPS が出てくるのか意味がわからない
768 名前:デフォルトの名無しさん mailto:sage [04/10/14 20:45:57] >>768 Continuation Passing Style のことだよ?
769 名前:デフォルトの名無しさん mailto:sage [04/10/14 21:25:50] >>767 の言いたいことを推測。 CPSで継続を陽に扱うには、最初から全部CPSで書かなくちゃならない。 CPSで書かれていないコードから呼ばれるコードで継続を取り出したかったら call/ccはプリミティブにならざるを得ない。 …ってなとこか? CPSでもMonadみたいな形で継続を隠すことはできるけど、それだって 最初からそのつもりで書いてないと。 個人的には、Schemeの継続は言語の実験をするための道具って 感覚が強いな。
770 名前:765 mailto:sage [04/10/14 21:44:13] >>769 言語の要素のプリミティブじゃなくて、 >>750 の > それこそ継続という概念が primitive なものであるということであり、scheme らしいところでは? > primitive なものさえあれば他の機能はそれらを組み合わせてできる。美しい。 の話。 (Schemeの)継続なんて無くてもCPSで書けば、gotoでもコルーチンでも call/ccでも(w実現できるんだから、プリミティブな(基底をなす)機能ではないんでは? ということ。 > 個人的には、Schemeの継続は言語の実験をするための道具って > 感覚が強いな。 同意。
771 名前:デフォルトの名無しさん mailto:sage [04/10/14 22:03:36] やたら継続を美しいと賛美しているのは、つい最近大学の 講義で継続を知って嬉しくなってる厨房だよね?
772 名前:デフォルトの名無しさん mailto:sage [04/10/14 22:11:31] >>771 はい。
773 名前:デフォルトの名無しさん mailto:sage [04/10/14 22:26:47] 四角いタイヤでも目盛がついていれば長さを測ったりできて便利かもしれんが、 それで高速道路を走るのは無理だ。
774 名前:デフォルトの名無しさん mailto:sage [04/10/14 22:37:43] で?
775 名前:デフォルトの名無しさん mailto:sage [04/10/14 22:42:13] ちんちんかゆいーー!
776 名前:デフォルトの名無しさん mailto:sage [04/10/14 22:44:58] >>775 切っとけ。
777 名前:デフォルトの名無しさん mailto:sage [04/10/14 23:38:01] >>770 だから?基底をなす機能しか使っちゃいけないなら、 ラムダだけ使えば? 理論上は統べての計算はラムダ式で可能なんだから、
778 名前:デフォルトの名無しさん mailto:sage [04/10/15 00:28:51] 継続がプリミティブだからエライと言い出した のは継続厨房でしょうが
779 名前:デフォルトの名無しさん mailto:sage [04/10/15 01:15:03] だからつかわなきゃいいじゃん threadだろうがcall/ccだろうが理解してない 人間がつかうと危険なのは当たり前。
780 名前:デフォルトの名無しさん mailto:sage [04/10/15 01:20:39] >>778 エライなんて誰も言ってないよ
781 名前:デフォルトの名無しさん mailto:sage [04/10/15 10:39:17] >>777 基底をなす機能しか使っちゃいけないなんて誰も言ってないよ。 >>779 理解している人間が使ったって危険なんですが。 というか、誰が使っても危険なものだということを理解していない人間は 理解している人間ではないでしょうね。
782 名前:ミミ mailto:sage [04/10/15 14:26:27] >> 個人的には、Schemeの継続は言語の実験をするための道具って >> 感覚が強いな。 >同意。 私も同意。 例外処理のような代替機能があれば十分だと思う。
783 名前:デフォルトの名無しさん mailto:sage [04/10/15 16:26:43] どういう場合になにが危険といってるの?実装といっしょにあげてみてよ。
784 名前:デフォルトの名無しさん mailto:sage [04/10/15 17:19:01] >>782 で、言語の実験で良い結果が得られたらその度に代替機能を実装してくの?
785 名前:デフォルトの名無しさん mailto:sage [04/10/15 17:29:19] >>783 危険っぽいコード (define go #f) (call/cc (lambda(cc) (set! go cc))) (call-with-input-file "foo" (lambda(port) (go port))) はわわ〜
786 名前:デフォルトの名無しさん mailto:sage [04/10/15 17:32:26] >>784 パフォーマンスを上げたいなら専用化した方がいいからね。 限定的な継続にして万能な部分を切っていく。 VBのバリアント型みたいなものだよ。
787 名前:デフォルトの名無しさん mailto:sage [04/10/15 17:45:17] >>784 良い結果がって言うよりさ、そもそも言語の設計で「良い悪い」を 判断するのって使ってみないとわからんわけじゃん。で、処理系 ネイティブに実装する方式だと、その処理系を使ってる人しか 試せない。だけどSchemeの場合、かなり凝ったことまで言語組み込み のプリミティブを組み合わせで書ける。そしたら、R5RS準拠の 処理系ならどれでもその提案を試してみることができるわけだ。 こいういう場合に使われるcall/ccなんかは、むしろ提案する 言語機能の仕様記述なわけよ。ところが、Schemeの場合は その仕様記述が動かせるプログラムになる。
788 名前:!= 782 mailto:sage [04/10/15 18:26:51] >>784 そう。実装してく。 whileやらbreakやらgeneratorやらに抽象化してそれを安全に使う。 call/ccはそれを作る道具であって、call/ccのスパゲッティを毎回 ほどいて、俺には解けるから危険じゃないとか言って喜ぶための ものじゃないと思うね。 上手い抽象化を考えたりその抽象化を実装したりするのに頭をつかおう。
789 名前:ミミ mailto:sage [04/10/15 18:27:43] >>784 実用上の開発では言語実装にまで遡って設計の見直しを図ることは稀でしょう。 もちろん継続があったらあったらでよいと思いますが、 C における goto よろしく、大規模な開発では原則として禁じるのが妥当ではないかと。 ソフトウェア工学上は継続は狼男だと言っている方がいらっしゃいましたが、 その視点におけるその意見には同意するということです。 >>785 それは継続の問題というよりも、 プログラミングの腕の問題という気が。。。 do でも論理エラーがあれば無限ループが書けるわけだし。 >>786 >パフォーマンスを上げたいなら専用化した方がいいからね。 >限定的な継続にして万能な部分を切っていく。 これに同意。 Scheme に継続しか用意しないというのは実用的ではないという感じがします。
790 名前:デフォルトの名無しさん mailto:sage [04/10/15 19:46:48] 「実用的な」制御構造がいずれも継続の上に(マクロで?)構築した ライブラリとして書けるっていうのがSchemeの主張なんじゃないの?
791 名前:デフォルトの名無しさん mailto:sage [04/10/15 19:52:56] 話がループしているのは継続のせいですか?
792 名前:デフォルトの名無しさん mailto:sage [04/10/15 20:06:32] じゃあ高速な継続の実装の仕方でも考えるかい?
793 名前:デフォルトの名無しさん mailto:sage [04/10/15 20:35:42] >>791 gotoのせいです。
794 名前:デフォルトの名無しさん mailto:sage [04/10/15 21:18:32] >>790 そう。 パフォーマンスとかが必要ならそれぞれの実装系においてライブラリ部分をCとかで実装していけばよい。
795 名前:デフォルトの名無しさん mailto:sage [04/10/15 22:36:02] 結局Schemeは非実用的ということですね
796 名前:デフォルトの名無しさん mailto:sage [04/10/15 22:39:54] わざわざ去勢する必要もなかろう
797 名前:デフォルトの名無しさん [04/10/16 01:39:19] CommonLispのマクロについての質問。 マクロはコンパイル時に評価を行う、ということは、コンパイルプロセスを 実行プロセスから分離することはできない、ということでOKでしょうか? また、関数の中でマクロが定義されている場合、関数が呼び出される度に マクロ展開(とコンパイル)が行われるのでしょうか?
798 名前:デフォルトの名無しさん mailto:sage [04/10/16 01:58:24] どういう動作をすると思ってるの?
799 名前:797 mailto:sage [04/10/16 02:06:33] 実行とコンパイルがインターリーブしていて、マクロの展開関数の中 から他の変数なんかも参照できる。その変数の値によって、展開の結果 が変わるかもしれない...というふうに"思って"います。 根本的に間違ってますか?
800 名前:デフォルトの名無しさん mailto:sage [04/10/16 03:39:45] 継続の話。 Kawa(Java による Scheme 実装)の継続は例外処理(try - catch) によって実装されているね。確か大域脱出しかできなかったような気 がする(Common Lisp の block 相当)。 実際、おれの場合、大域脱出くらいでしか継続は使ったことないな。
801 名前:デフォルトの名無しさん mailto:sage [04/10/16 04:37:48] >>797 >コンパイルプロセスを実行プロセスから分離する lispには eval関数の様に実行時に式を評価する仕組みがあるので コンパイル環境と実行環境を分離するのは難しいと思う。 でもこの話は、マクロとは関係ないような気がする。 >関数の中でマクロが定義されている場合 関数内でマクロを定義した場合の動作など考えたことが無かった。 で、やってみた。 ;; 関数定義 (defun test (x) (cond ((equal x 1) (defmacro m () 10)) ((equal x 2) (defmacro m () 20)) (t nil)) (m)) ;; 実行結果 ・・・ clisp の場合 (test 0) => 20 (test 1) => 20 (test 2) => 20 ;; 実行結果 ・・・ xyzzy lisp の場合 (test 0) => 関数が定義されていません: m (test 1) => 10 (test 0) => 10 (test 2) => 20 (test 0) => 20 xyzzyではマクロ展開を実行時に行っていて、clispでは関数定義時に 行っているようだ。CLtL2 的にはどうなっているんだろう?
802 名前:デフォルトの名無しさん mailto:sage [04/10/16 08:26:44] 重複定義でエラーが正解
803 名前:デフォルトの名無しさん mailto:sage [04/10/16 09:41:37] >>801 その例は実行時までプログラムの意味が決まっていないよね? そういうマクロはたとえ可能としても悪いマクロだと思う (実際おれは不可能と思ってたし) 役に立つ場合って何かあるかな?
804 名前:デフォルトの名無しさん mailto:sage [04/10/16 15:10:07] >>797 > また、関数の中でマクロが定義されている場合、関数が呼び出される度に > マクロ展開(とコンパイル)が行われるのでしょうか? コンパイルされたコードの中でのマクロ展開はコンパイル時に行われて、 実行時には再度行われない、てことになってます。 ですから、関数内でマクロを再定義するようになっていたとしても、 展開に使われる手続きはコンパイル時の環境にあるものになるはずです。 コンパイルしない場合には、何時、何度展開されるかは実装依存です。 cf. www.lisp.org/HyperSpec/Body/sec_3-2-2-2.html >>801 xyzzy でもコンパイルすると clisp と同じ結果になりますね。 でもいまいちピンとこない結果だなあ。 (defmacro m () 20) は展開時には、つまりコンパイル時であれ関数定義時であれ、評価されませんよね? だったら (m) は展開できない気がするんですが。勘違いしてる?
805 名前:ミミ mailto:sage [04/10/16 15:19:43] > (defmacro m () 20) は展開時には、つまりコンパイル時であれ関数定義時であれ、評価されませんよね? リーダが読み取って、最適化された内部構造体に変換するときに、 ついでに defmacro を評価してしまうという実装はあり得ると思う。 (そんな処理系を見たことがある気がする。) その場合、最後に出てきた m の定義によってオーバーライドされてしまうので、 上記のような結果になるのでは。
806 名前:804 mailto:sage [04/10/16 15:34:00] >>805 あーなるほど、それなら納得いきますね。 確かに普通それで問題ないでしょうし。
807 名前:デフォルトの名無しさん mailto:sage [04/10/16 16:17:58] そういうマクロはエラーにして欲しいなあ。 eval介入するならともかく、使い道なんてないでしょ。
808 名前:デフォルトの名無しさん mailto:sage [04/10/16 17:47:56] Gaucheはエラーになった
809 名前:デフォルトの名無しさん mailto:sage [04/10/16 18:00:35] >>808 GaucheってSchemeでしょ? Scheme的には>>801 て文法的にありえんし… mのスコープが意味不明。
810 名前:デフォルトの名無しさん mailto:sage [04/10/16 18:27:24] >>797-799 > また、関数の中でマクロが定義されている場合、 これって macrolet のことを言いたいのかなあ、とふと思った。 > 実行とコンパイルがインターリーブしていて、マクロの展開関数の中 > から他の変数なんかも参照できる。その変数の値によって、展開の結果 > が変わるかもしれない...というふうに"思って"います。 これについては、こんな例もあるかな。 (defvar *foo*) (defmacro %foo (x) `(,(if *foo* 'car 'cdr) ,x)) (defun foo (ls key) (let ((*foo* key)) (%foo ls))) として、 (let ((ls '(a b c))) (values (foo ls t)(foo ls nil))) => ? , ? とりあえず今手元にある xyzzy では、コンパイルしないと a , (b c)、 コンパイルするとコンパイル時の *foo* の値によって a , a or (b c) , (b c) が、 更に *foo* の値が未定義だと (b c) , (b c) が返ってきました。 ……しかし、どうにも病的な例しか思い浮かばないなあ。