継続マラソン1

id:higepon:20061219:1166544588
某所で捕捉されたのでコードを晒します。
僕は本当に頭が悪いので全然理解できていないです。いつか理解できると良いな。
動作確認はGaucheでやっています。

公開することを考えていなかったので謎のコメントやらコピペに近いものがあったりしますが御容赦を。

;; 継続のお勉強
;; http://www.stdio.h.kyoto-u.ac.jp/~hioki/gairon-enshuu/SchemeNotes/continuation.html
(define p (lambda (m)
            (display m)
            (newline)))


;; 継続c をよびだしていないので call/cc の値は 12
(p (+ 2 (call/cc (lambda (c) (* 3 4)))))

;; 継続c をよびだしているので 2を足す継続に4が作用されて 6になる
(p (+ 2 (call/cc (lambda (c) (* 3 (c 4))))))

;; 継続を変数に入れる
(define cont #f)
;; 継続をセットしているだけで呼び出していないので 14をになる
(p (+ 2 (call/cc (lambda (c) (set! cont c) (* 3 4)))))

;; 2を足す継続
(p (cont 2))
(p (cont 5))

;; 別の例
(define x 0)
(define y 2)
(define cont #f)
(p (list x (call/cc (lambda (c) (set! cont c) 1)) y))

;; contは 0、contの引数、yを評価したリストを作る継続
(p (cont 3))

;; xをかえてみるけど影響ないよ。なぜならxの評価は終わった後の継続だから
(set! x 4)
(p (cont 3))

;; yを変えると影響あり
(set! y 4)
(p (cont 3))

;; もっと具体的な例
;; 与えられたリストの積を出す
(define (mul l)
  (p l)
  (let ((result
         (if (null? l)
             1
             (* (car l) (mul (cdr l))))))
    (p (list result l))
    result
  ))

;; 24
(p (mul (list 1 2 3 4)))

;; 途中に0があるから絶対ゼロなのに無駄だよね
(p (mul (list 1 0 3 4)))

;; 大域脱出するパターン
;; 分からない

;; イメージコード
;; (define (mul l)
;;   (p l)
;;   (let ((result
;;          (if (null? l)
;;              1
;;              (if (= 0 (car l)) (脱出して0を返してほしい) (* (car l) (mul (cdr l)))))))
;;     (p (list result l))
;;     result
;;   ))

;http://ja.wikibooks.org/wiki/Scheme_%E7%B6%99%E7%B6%9A


(define (f x)
  (+ x 1))

(define (g x)
  (+ x 2))

(define (h x)
  (+ x 1))

;; 入力 => [ f => g => h ] => 結果
(p (h (g (f 1))))

;; 入力 => [ f => 1 => h ] => 結果
(p
(h
  (call/cc
    (lambda (cont-proc) ;; 継続手続きをとり出す
       (let ((v (f 1)))
         (cont-proc 1)      ;; 継続手続きに1を渡す
         (g v)                    ;; ここでgを呼び出しているが、使われない
      ))))
)

;; f からの入力が3のときだけ 1
(p
(h
  (call/cc
    (lambda (cont-proc) ;; 継続手続きをとり出す
       (let ((v (f 2)))
         (if (= 3 v)
             (cont-proc 1)      ;; 継続手続きに1を渡す
             (g v)                    ;; ここでgを呼び出しているが、使われない
             )))))
)


;;現在の継続を手続き (継続手続き) にパッケージ化して、それを引数として procを呼び出します。
;;procが戻ったら、その返り値がcall/ccの値となります。
;;作成された継続手続きがどこかで0個または複数個の引数を伴って呼ばれたら、あたかもcall/ccから戻ったかのように実行が継続されます。
;;その場合、 call/ccは、継続手続きに与えられた引数を複数の値として返します。
(define (proc c) (p "[proc]") 1)
(p (proc #f))      ;; この
(p (call/cc proc)) ;; 2つは同じ

(define cont #f)

;; 継続手続きを保存してみる
(define (proc c) (p "[proc]") (set! cont c) 1)
(p (call/cc proc))
(cont 3) ;; 確かに継続手続きは3を返すけどありがたみが分からない。

;; もっと作業途中っぽい感じを作ろう
(define cont #f)
(begin
  (p "hello")
  (p (call/cc (lambda (c) (set! cont c) "call/cc")))
  (p "world"))

;; call/cc? worldとなったね
(cont "call/cc ?")

;; こういうのはどうだろう
(define back #f)
(define (your-life)
  (p "your life start")
  (p "1 year old")
  (p (call/cc (lambda (c) (set! back c) "2 years old")))
  (p "3 years old")
  (p "want to be younger? y/n")
  (let ((c (read-line)))
    (if (equal? c "y")
        (begin (p "equal") (back 1)))
    (p "4 years old")))

;; おおすごい!
;;(your-life)


;; 本当にそのときの環境を保持しているのかな?
(define back #f)
(define (your-life)
  (define i 0)
  (p "your life start")
  (p "1 year old")
  (p (call/cc (lambda (c) (set! back c) "2 years old")))
  (p i)
  (set! i (+ i 1))
  (p "3 years old")
  (p "want to be younger? y/n")
  (let ((c (read-line)))
    (if (equal? c "y")
        (begin (p "equal") (back 1)))
    (p "4 years old")))

;; うんとiはインクリメントされるね。つまり順序だけなのか.
;;(your-life)


;; 今日プールで泳いでいたら大域脱出のコードが書ける気がしたので書いてみる
;; setjmp/longjmp的?な使いかた

(define num-list (list 1 2 3 4 5 6))
(define (sum l)
  (let* ((cont #f) (value (call/cc (lambda (c) (set! cont c) 0))))
    (define (sum-iter ll s)
      (if (null? (cdr ll))
          (cont s)
          (sum-iter (cdr ll) (+ s (car ll)))))
    (if (not (= 0 value))
        (begin (display "escape") value)
        (sum-iter l 0))))

;; できた!
(p (sum num-list))

;; gotoとは違う感じ。大域脱出が出来ることは分かった。
;; これが役に立つ場面はそんなにないから本質ではないだろう。