2010/03/24

find-fold

プログラミングGauche」の継続のところをチラ見して。CPS難しいー。このコードの後、もっとCPSです。「厳密にCPS変換するとこうなるよ」ってのが載ってましたがギブ。

プログラミングGauche

Re:filter*

こんな感じで↓。

お陰さまでかなりすっきりしました(笑)

Scheme:初心者の質問箱

こんなのがあった。

(begin a b ...)と(let () a b ...)は同じじゃない

コメントでご指摘頂いてました。ここに改めてメモとして残しておきます。
Scheme の begin には面白い特徴があります。
新しいスコープを作らないのです。
なるほど。知りませんでした。(「RnRS読め」ですよね)
例えば ↓ こんなコードでエラーが起こりません。
(begin (define a 1))
(display a)
ホンマや。
Scheme
1
2
(begin (define x 100))
(display x)



Output:
1
100

a はトップレベルで定義されたことになります。
記事中のコードは begin と let のどちらを使っても問題ないと思いますが、同等と考えていると不意につまづくこともあるかもしれません。
begin のこの性質はマクロを書くときに必要になることがあります。
まんまと(let () a b ...)で(begin a b ...)と同じことできるなら、begin要らなくね?などと思っちゃってました。勉強になりました。ありがとうございました!


追記

(let ((x 1))
  (define x 2)
  x)
2

(let ((x 1))
  (let ()
    (define x 2))
  x)
1

(let ((x 1))
  (begin
    (define x 2))
  x)
2


2010/03/23

よくわかるcall/cc

「打ち消し線」すごくわかりやすい!
内容に直接関係しないのですが、「スタックのコールバック」。@aharisuさんが言っていたのはたぶん「コールスタックの破棄」的なことだったかと。コールスタックごと吹き飛ばす的な。違ったかな。

継続あれこれ

眺めてたら途中で力尽きた。
「ある時点での状態」を変数に束縛して、後からそこへ戻るといったことも可能になる。Schemeの継続は関数の形をとっており、これは「その関数を呼ぶことにより、そこに渡された引数をcall/ccで囲まれている式全体の値として継続に“注入”できる」と定義されている。
プログラムの実行順序を制御する概念
既に終了したスタックフレームを黄泉の国か ら引きずり出してスタックにぶちこめるわけである。
普通の人間が「おっ、ここはCall/CCを使えば カッコ良く実装できるね!」などと思いついたりすることはまずありえない
継続を用いれば大域脱出、コルーチン、疑似マルチタスク、バックトラックといった特殊な制御を必要とするプログラムを効率的に記述することができる
「分かれば分かる」
継続は現在の計算を続行するための情報 
どんなコードでも継続渡し形式として「見る」ことができる 
現在の継続を手続き (継続手続き) にパッケージ化して、それを引数として procを呼び出します。procが戻ったら、その返り値がcall/ccの 値となります。
言語によっては、呼び出し元の関数が分からず呼び出したらもう戻ってこ ないものもあります。呼び出し元の関数に値が返ってくるのは、どこから自分を呼び出したのかという情報をどこかで管理し、呼び出された側はその 情報を元に値を返すという決まりがあるからです。 
保存した継続を動かしてみましょう。
(* 2 (fact 10))という計算は、fact/cpsを使えば次の式と等価です。(fact/cps 10 (lambda (a) (* 2 a)))
継続渡し形式で書けば、現在実装中の関数が、 どういう形で結果を返すのが良いかの設計を遅らせることが出来ます。
継続は保存してから呼び出されるまでの間、完全に休眠しており、 その間にいかなる式の評価でもはさむことが出来ます。 
(call/cc (lambda (return) ...)) は説明すると長くなるけど、まあ、 returnってラベルを定義してるもんだと思ってくれればいい。

S式

これこれ。頭でわかってるつもりでも、実際なかなか書けない・・・。

(cond ((negative? x)
  (display 'foo)
  (newline))
 ((zero? x)
  (display 'bar)
  (newline))
 (else
  (display 'baz)
  (newline))))
  (newline))))
(begin (display (cond ((negative? x) 'foo)
   ((zero? x) 'bar)
   (else 'baz)))
  (newline)))

2010/03/22

TSS rember1*, let/cc, try

rember1*はThe Seasoned Schemerに何度も出てくる練習問題です。

例えば
(rember1* 'meat '((pasta meat) pasta (noodles meat sauce) meat tomatoes))
; -> ((pasta) pasta  (noodles meat sauce) meat tomatoes)
というようなものです。

The Seasoned Schemerでは、一般的な再帰やlet/ccを使った例が出てきますが、いまいちです。いまいち、というかすごくわかりにくいです。
取り合えず、以下のコードが14章にでてくるlet/ccとtryを使った例です。

2010/03/19

TSS leftmost, let/cc, named-let

let のこんな使い方は驚きました。begin とか progn と同等と考えて良さそうですね。
(let () a b . . .)


コードの方↓は、なんともゴチャゴチャしてしている。

ところで明日は 9LISP


The Seasoned SchemerプログラミングGauche

TSS letting, scramble, fold2

11章に出てきたscrambleをlettingするエクササイズらしい。
foldでは書けないよなー、と思い探してみるとfold2なるものがgauche.collectionにありました。


reverse格好悪い・・・。


追記


The Seasoned SchemerプログラミングGauche