Scheme使いの皆さまへ
■ このスレッドは過去ログ倉庫に格納されています
0001デフォルトの名無しさん
NGNGlambdaの使い方ぐらいはわかるCプログラマにわかるように
call/ccを説明してくれませんか?
プログラミング言語 SCHEMEとか読んだのですがさっぱりです。
call/ccを呼び出すと現在実行中の位置の情報が渡されて
それを呼び出すとその位置へ戻る。とかなのかなと思いますが、、
おおっ!!っと来ないんです。。。
0002デフォルトの名無しさん
NGNG0003デフォルトの名無しさん
NGNG大域gotoです。(たぶん)
様はC言語のsetjumpとlongjumpです。(たぶん)
私も最近Schemeを勉強中なのでよくわからないです。
日本語に訳す(?)と「継続」ですか。余計わからないです。
こういうときにcall/ccを使え!っていう様な適切なサンプルがあれば良いんですが。
00043
NGNG'='で括って言い切ってますが、ホントですか?
知っておられるのならサンプルを出していただけると助かります。
0005デフォルトの名無しさん
NGNG0006デフォルトの名無しさん
NGNG0007デフォルトの名無しさん
NGNGと言ってもこの二三年で二三冊みたいだけど。
0008デフォルトの名無しさん
NGNGGNUプロジェクトのおかげでしょう。
Guileだっけ?
0010デフォルトの名無しさん
NGNGて、call/ccの引数である手続きに渡す関数です。といわれてもよくわからな
いと思うので例をあげますと、
(define (bar x)
"hello")
(define (foo)
(display (call/cc bar))
)
のcall/ccは、とりあえず
(lambda (y) (display y))
というクロージャを作って、それをbarに渡された関数に渡します。barではこ
のクロージャがxにバインドされますが、barでは渡された引数を無視して
"hello"を返しているので、これがcall/cc呼び出しの値になって
"hello"
と表示されます。
一方、barを
(define (bar x)
(x "hello")
)
とすると、xにバインドされたクロージャを呼び出すことになります。ただし、
call/ccの引数として与えられた手続き内で渡された継続を実行するとそれ以
降はキャンセルされるので、「呼び出す」というよりは「ジャンプ」に近いも
のになります。この場合、渡された継続に"hello"を渡しているので、それが
call/cc呼び出しの値となって、結局また
"hello"
と表示されます。
0011デフォルトの名無しさん
NGNG継続の区間をハードウェアスタックに持つか、ヒープに持つかで実行速度に影響が出そう。
ハードウェアスタックを使う実装の場合は継続の切り替えでスタック領域のコピーを行なう。
CPUの機能でスタックを一瞬で切り替えられる環境なら別だけど、移植性は低い。
ヒープに持つ実装の場合は単にプログラムカウンタが移動するだけ。移植性は高い。
・・・という推論は正しいですか?
0012デフォルトの名無しさん
NGNG00131
NGNGなるほどー。
call/ccに渡すlambdaが呼び出される時に
call/ccを呼び出した時の継続(??スタックとかの状態と考えればいいのかな...)が
渡されて来る。
そして、もし、それを呼び出すと、その継続の所にジャンプして
呼び出した時の引数が返される。
というわけですか????
こんなの書いてみました。
(define call/cc call-with-current-continuation)
(define print (lambda args (for-each display args) (display "\n")))
(define bar (lambda (x) "こんにちは"))
(define bar2 (lambda (x) (x "現在の実行を停止してこの文字列を評価した結果とします") "こんばんは"))
(print (call/cc bar))
(print (call/cc bar2))
関数から戻るのにも使えそうですね。。。
(print (call/cc (lambda (return) (return "関数から戻ります。") "本当の戻り値")))
mywhileなんてのも作れそうです。
00141
NGNGなんかすごいなぁ。。。
しかし内部でどうなってんのかさっぱりです。
(define jump-to-func-in ())
(define func-hoge
(lambda ()
(print "こんばんは。")
(call/cc (lambda (x) (set! jump-to-func-in x)))
(print "私は今、Schemeのcall/ccの勉強をしています。")))
(func-hoge)
(jump-to-func-in #f) ;引数に意味はない???
00151
NGNGcall/ccの実装がどうなってるのかとても興味あります。
0016デフォルトの名無しさん
NGNGシンボルや文字列とかは別にするけどね。
0017デフォルトの名無しさん
NGNG0018デフォルトの名無しさん
NGNG0019デフォルトの名無しさん
NGNGあったような気がするな……
00201
NGNGC言語で言う関数からのreturn(return 10;とか。)は
(define call/cc call-with-current-continuation)
(display (call/cc
(lambda (return)
; return 10;
(return 10))))
こんなのでそれっぽく出来ますがLispじゃどうするんでしょう?
00211
NGNGこんな感じですか?
typedef struct
{
ObjectType type;
union
{
int num;
char *str;
Symbol sym;
struct
{
Object *car;
Object *cdr;
} cons;
} u;
} Object;
consのcarとcdrを使えば配列、連想配列とかも実現出来ますね。
それと、最近知ったのですがA-listというのは
連想配列のことをらしいです(始めは何のことかわからなかった(EmacsLispのマニュアルで知りました))。
0022デフォルトの名無しさん
NGNGreturn っていうか、最後に評価した値が関数の値になる。
;; elisp しか知らないから間違いだらけかもだけど。
こんな感じ。
(defun foo (flag)
(if flag
"true"
"false"))
あと、局所脱出での return ってんだったら、throw catch ってのを使う。
(catch 'loop
(while t
(when (test)
(throw 'loop "escape!"))))
0023デフォルトの名無しさん
NGNGSchemeインタプリタで、だらだらと記述した全てのスクリプトをファイルに保存したいのですが、
そういった事は標準手続きで可能でしょうか。
その保存したファイルを次回の立ち上げ時に読み込ませるとあら不思議、以前と同じ状態になりました。
ってのが良いんですが。
002423
NGNG00251
NGNG(transcript-on filename)
(transcript-off)
ってがあるみたいですがGuileでは使えませんでした。
Lispの動的さを利用して、、
(while 1
(set! tmp (read)
;ファイルに書きだす
(eval tmp))
とか。。。
002623
NGNG002723
NGNG002823
NGNG77行足らずでこういう事が出来てしまうのか・・・。
0029デフォルトの名無しさん
NGNG0030age
NGNG0031デフォルトの名無しさん
NGNG0032デフォルトの名無しさん
NGNG一般的な方法はどうなんだろ。
0033デフォルトの名無しさん
NGNG僕も schemeに興味あります。(使えませんが...)
こんな webページがあったりしますね。
http://www.sci.toyama-u.ac.jp/~iwao/Scheme/
MLとかは無いのかなぁ?
0034デフォルトの名無しさん
NGNGGIMP系の日本語MLならあったような・・・。(GIMPはGuileを使ってる)
さっき軽く検索エンジンかけたけど、Scheme系の話題ってほんと少ないね。
0035デフォルトの名無しさん
NGNGデータ表現としてのセルの構造はかなり便利だね。
早速自作ライブラリに組み込んだよ。
car
cadr
caddr
cadddr
:
assq
assv
assoc
003633
NGNG0037デフォルトの名無しさん
NGNG0038デフォルトの名無しさん
NGNG0039デフォルトの名無しさん
NGNG例:
f(x) + 2 + -1;
↓
(+ (f x) 2 -1)
0040デフォルトの名無しさん
NGNG(+ (f x) 2 -1)
↓
(+ (f x) 1)
0041デフォルトの名無しさん
NGNGどっかにありませんか?
0042デフォルトの名無しさん
NGNG>>38
call/ccを含んだコアの部分くらいなら簡単だけど、R5RSフルセットは
面倒なのでパス。
>>39-40
宿題は自分でやろうね
>>41
これはまたクラシックな。SECDマシンの論文だよね。たしか1964年の
Computer Journalじゃなかったっけ。こんなのオンラインであるのか
なあ。どっかの大学の図書館に頼むのが手っ取り早いと思うけど。
0043デフォルトの名無しさん
NGNG(eval (read))
じゃだめなの?
0044いつでもどこでも名無しさん
NGNG004539>42
NGNGせっかくネタ提供してんのに終っちまうじゃん
授業教えてたんならこの程度ささっと書いてくれよ〜
0046デフォルトの名無しさん
NGNGもう字句解析はできたと仮定して、
((f x) plus 2 plus -1)
というリストから変換するなら、わりと簡単にできるかな。
中置記法のカッコをなにか別の記号で置きかえといたほうがいいので、
たとえば (1+2)*3 なら
(leftparen 1 plus 2 rightparen asterisk 3)
に変換されるとか、そんなふうにとり決めてやってみようか。
004739
NGNG-1の'-'は単項演算子(前置)とする。
当然ながら二項演算子'+'の優先順位は単項演算子よりも低い。
解析フロー
| f ->シンボル
| () ->後置演算子:関数呼出
| (引数解析開始)
| x ->シンボル
| (引数解析終了) ;(f x) 確定 (push1)
| + ->二項演算子(左結合)
| 2 ->定数 ;(+ push1 2) 確定 (push2)
| + ->二項演算子(左結合)
| - ->単項'-'
| 1 ->定数 ; (+ push2 -1) 確定 (push3)
↓
この後、push2とpush3の先頭プリミティブの'+'は優先順位が同じなので展開し、
(+ (f x) 2 + -1) が得られる。
004839
NGNG(+ (f x) 2 -1) が得られる。
004939
NGNGその先頭の演算子で畳み込むと
(+ (f x) (+ 2 -1))
↓
(+ (f x) 1) が得られる。
Cなどの手続き型言語での実装なら直ぐに思い付くけど、
こういった処理をScheme流で奇麗に書くとするとどうする?
とりあえず
単項演算子は前置+,- 後置()のみ
二項演算子はSchemeにも存在する+,-,*,/ など。
シンボルはSchemeの字句解析で得られる物で良い。
(parse '(f (x) + 2 + -1)
=> (+ (f x) 1)
0050名前ついてますか?
NGNGつーか、単なる compilerの問題じゃ。
LL parsingが楽そうだけど、adhocな演算子優先順位解析も好き。
0051デフォルトの名無しさん
NGNG0052デフォルトの名無しさん
NGNG解析するとき普通、解析木を全部作っちゃうんですか?
作りつつ、traverseしつつ、ですよね?
005339
NGNG構成は既に知ってるんだけど・・
Schemeでどうやるかが知りたいの。
005439
NGNG(define stack '())
(define (stack-push obj)
(set! stack (cons obj stack)))
(define (stack-clean)
(set! stack '()))
(define (stack-pop)
(if (null? stack)
(begin
(display "stack is empty\n")
#f)
(begin
(set! stack (cdr stack))
stack)))
Schemeで名前の解決はどうやるんだろう。
例えば、上のstack-push/popを別インスタンスに対して行いたい場合。
いちいちインスタンス指定して
(stack-push 'stack1 obj)
ってやるしかない?
005539
NGNG005639
NGNG005739
NGNG(define stack '())
(define (stack-push obj)
(set! stack (cons obj stack)))
(define (stack-clean)
(set! stack '()))
(define (stack-pop)
(if (null? stack)
(begin
(display "stack is empty\n")
#f)
(begin
(set! stack (cdr stack))
stack)))
lispのインデントって普通2文字?
005839
NGNG(define (unary-expr tokenlist)
(define unary_op
'(+ -))
(let ((unary (memq (car tokenlist) unary_op)))
(if (not unary)
(primary-expr tokenlist)
(let ((result (unary-expr (cdr tokenlist)) ))
(stack-push (cons 'unary (cons (car unary) '())))
result))))
005939
NGNG(let ((primary (car tokenlist)))
(cond
((or (symbol? primary) (number? primary))
(let ((result (post-expr (cdr tokenlist)) ))
(stack-push (cons 'primary (cons primary '())))
))
((pair? primary) (expr primary))
(else #f)
)))
006039
NGNGまあいいか。
006139
NGNG(cond
((and (pair? tokenlist) (pair? (car tokenlist)))
(begin
(stack-push (cons 'func (cons (car tokenlist) '()) ) )
(cdr tokenlist)
))
(else tokenlist)))
006239
NGNGこの程度だったらCでフロントエンド作った方が良いな・・
0063デフォルトの名無しさん
NGNG(string-ref "あイいん" 0)
=>#\あ
(string-ref "あイいん" 3)
=>#\い
が返る様な実装の。
それにしても・・使ってる奴誰もいない様だな(泣
0064デフォルトの名無しさん
NGNG保存するから内側にも飛んでいける。
0065デフォルトの名無しさん
NGNGそんな話題とっくに終ってるのに。
・・おっと失礼
0066デフォルトの名無しさん
NGNG開発途上みたいですが
http://www.shiro.dreamhost.com/scheme/gauche/index-j.html
はどうですか?
% cd src
% ./gosh
gosh> (string-ref "Scheme処理系" 8)
#\系
gosh> (sqrt -5)
0+2.23607i
gosh>
0067デフォルトの名無しさん
NGNGおあ、知ってる人がいた・・
紹介ありがとうございます。
こういう実装をする場合、文字列も2バイト(マルチバイト)で管理してるのだろうか。
そうしないと参照するたんびに頭からなめていかなきゃならないし。
でも半角だけだったら領域がもったいないかなあ・・
(string-ref 8)
(make-string "Scheme処理系")
-------------------------------
|S |c |h |e |m |e |処|理|系|\0|・・・・
-------------------------------
|2 |2 |2 |2 |2 |2 |2 |2 |2 |2 |←各文字の長さ(Byte)
-------------------------------
↓
(make-character)
|系|
#\8c6e
文字列に対してのみ(内部的に)ポインタ型を作れば効率良いかな?
0068デフォルトの名無しさん
NGNGうーん、しょうがないか。
日本語を自然に扱えるメリットの方が大きいし・・
0069デフォルトの名無しさん
NGNG0070デフォルトの名無しさん
NGNG0071デフォルトの名無しさん
NGNG切り分けた方が良いかな。
でもstring-set!されたら・・アウトだ。
そのときは新たに拡張文字列を生成するかな。
あ、でもそうするとそれを参照してるセルを全部付け替えなきゃならないからだめだ。
0072デフォルトの名無しさん
NGNGかなりのオーバーヘッドの様な・・めんどうだなあ。
■ このスレッドは過去ログ倉庫に格納されています