TheSeasonedSchemer

今日の xhago2 では LISP 系の発信がありましたのでとりあえず満足。ちなみに括弧は取り除くものではありません。
それは良いとして、github なリポジトリから clone を。

$ git clone https://github.com/hanachin/TheSeasonedSchemer.git

とりあえず中身を確認。

$ for i in `ls` ; do echo $i; cat $i; echo ""; done
11.scm
(define atom?
  (lambda (x)
    (and (not (pair? x)) (not (null? x)))))

(define add1
  (lambda (x)
    (+ x 1)))

(define sub1
  (lambda (x)
    (- x 1)))

(define one?
  (lambda (x)
    (= x 1)))

;; p7
(define two-in-a-row-b?
  (lambda (preceding lat)
    (cond ((null? lat) #f)
          (else (or (eq? (car lat) preceding)
                    (two-in-a-row-b? (car lat) (cdr lat)))))))

;; p7
;; アトムが連続して2回現れるかどうかを調べる(改訂版)
(define two-in-a-row?
  (lambda (lat)
    (cond ((null? lat) #f)
          (else (two-in-a-row-b? (car lat) (cdr lat))))))

;; p10
(define sum-of-prefixes-b
  (lambda (sonssf tup)
    (cond ((null? tup) '())
          (else (cons (+ sonssf (car tup))
                      (sum-of-prefixes-b (+ sonssf (car tup))
;; p11
(define sum-of-prefixes
  (lambda (tup)
    (cond ((null? tup) '())
          (else (sum-of-prefixes-b 0 tup)))))

;; p13
(define pick
  (lambda (n lat)
    (cond ((one? n) (car lat))
          (else (pick (sub1 n) (cdr lat))))))

;; p13
(define scramble-b
  (lambda (tup rev-pre)
    (cond ((null? tup) '())
          (else (cons (pick (car tup)
                            (cons (car tup)
                                  rev-pre))
                      (scramble-b (cdr tup)
                                  (cons (car tup)
                                        rev-pre)))))))

;; p14
(define scramble
  (lambda (tup)
    (scramble-b tup '())))

notes.org
* The Seasoned Schemer
** このメモについて
   Scheme修行を読んで本文で気になった部分や感想などを書いていく。
*** TODO このメモ書きからブログを作成するためのorg-modeの使い方を覚える
** 訳者前書き
*** 2章合わせてSchemeの入門書として完結
*** The Little Schemerと同じく質問とそれに対する答えという形式
*** 前作では「再帰的」な考え方、今回は継続と代入
*** 他の言語では大域的な脱出手段としてはあるがSchemeのようにいつでも使えるわけではないらしい
** 序文
*** 「もし誰かに魚をあげたら、一日食べることができる。もし誰かに釣りを教えたら、一生食べることができる。」
*** Lispは元々「LISt Processor」Lispにはリストがなければならないが。リストはLispの心臓。
*** しかし関数も必要。関数は魂。
*** Scheme手習いは言うなれば魚。生きるためには一日の魚だけでは足りない。今度は釣りを習う番!
** はじめに
*** 「この本の目的は、読者に計算の性質について考えることを教えることにある。」
*** プログラミングの実用的な世界への入門書ではないが、計算の性質を理解する出発点
**** ガイドライン
***** 急いで読んではだめ。5回未満で読み切ろうとしないこと。(ちなみにScheme手習いには2回未満で読み切ろうとしないこと、と書いてる)
***** 飛ばして後ろから読んではだめ。少しずつ難しくなっていく。
***** 「読みながら例を試す」
****** Gaucheで試しながら進める。
****** 関数については本の中の質問を拾ってテストケースを書く。
****** なるべくテストケースを書いてから関数を定義するようにする。
***** TODO 本にちりばめられたヒントから自分の定義を形式化し、覚え、理解する!
***** しかし戒律はその先を読む前に知って理解しておくこと。
** Chapter 11
*** Scheme手習いの続きなので11から始まる。
*** 究極のλを知っていますか?
*** two-in-a-row-b?は2つの引数が変わるのに、質問は1つの引数についてのみ
**** 今までのものとちょっと違う
**** 先行する要素を引数に取っている
*** p10「一方の引数は他方の引数について関数に何かを伝えます」
**** このトリックは面白いなぁ
**** two-in-a-row-bのprecedingでは他方の引数の前の要素を
**** sum-of-prefixes-bのsonssfはこれまでの全ての数の合計を
**** scramble-bのrev-preは自分より前の部分の逆を
*** 第11の戒律「ある関数が、その関数に対する他の引数がいかなるものか知る必要があるときは、付加的な引数を用いるべし。」
*** 出てきてる用語
**** parsleyはパセリ
**** sardinesはイワシ
**** TODO tupは(なんだったっけ)
**** sonssfは「sum of numbers seen so far.(それまで見てきた数の合計)」の略
**** scrambleのニュアンスがちょっと分からない
**** rev-preはreversed prefix
*** 前章で定義したone?やpickなどの手続きを別途定義した
*** 「関数の手がかりは、いつだってその名前です。」
**** いい名前は理解を助けてくれますね。
*** 食事の回数、3回
**** p13 「覚えているならアイスクリームを食べましょう」
**** p15 「スナックを食べる前に」
**** p15 「お茶の時間です。」
**** 「はじめに」によると「食べ物がちょっとした気晴らしになってこの本を一度にたくさん読まないで済むことを願っている」らしい。
***** でも面白いから読み始めると1章、一気に読んでしまう。

README
Scheme修行読書用のリポジトリです。
test11.scm
(use gauche.test)
(add-load-path ".")
(load "11")

(test-start "chapter 11")

(test-section "two-in-a-row?")
;; p3
(test* "(two-in-a-row? '(Italian sardines spaghetti parsley))"
       #f
       (two-in-a-row? '(Italian sardines spaghetti parsley)))
;; p4
(test* "(two-in-a-row? '(Italian sardines sardines spaghetti parsley))"
       #t
       (two-in-a-row? '(Italian sardines sardines spaghetti parsley)))
(test* "(two-in-a-row? '(Italian sardines more sardines spaghetti parsley))"
       #f
       (two-in-a-row? '(Italian sardines more sardines spaghetti parsley)))
;; p9
(test* "(two-in-a-row? '(b d e i i a g))" #t (two-in-a-row? '(b d e i i a g)))

(test-section "sum-of-prefixes")
(test* "(sum-of-prefixes '(2 1 9 17 0))"
       '(2 3 12 29 29)
       (sum-of-prefixes '(2 1 9 17 0)))
(test* "(sum-of-prefixes '(1 1 1 1 1))"
       '(1 2 3 4 5)
       (sum-of-prefixes '(1 1 1 1 1)))

(test-section "scramble")
(test* "(scramble '(1 1 1 3 4 2 1 1 9 2))"
       '(1 1 1 1 1 4 1 1 1 9)
       (scramble '(1 1 1 3 4 2 1 1 9 2)))
(test* "(scramble '(1 2 3 4 5 6 7 8 9))"
       '(1 1 1 1 1 1 1 1 1)
       (scramble '(1 2 3 4 5 6 7 8 9)))

(test-end)
$

およ、なんか普通の試験が書いてあるぞ。
あと、scramble あたりの意味がよく分からん。以下を手で展開してみることに。

(scramble-b '(1 2 3 4 5 6 7 8 9) '())

一周目。

(cons (pick 1 (cons 1 '()))
      (scramble-b '(2 3 4 5 6 7 8 9)
                  (cons 1 '())))

二周目。(pick 1 (cons 1 '())) は 1 ということで。

(cons 1
      (cons (pick 2 (cons 2 '(1)))
            (scramble-b '(3 4 5 6 7 8 9)
                        (cons 2 '(1)))))

三周目。(pick 2 '(2 1)) は 1 ですね。

(cons 1
      (cons 1
            (cons (pick 3 (cons 3 '(2 1)))
                  (scramble-b '(4 5 6 7 8 9)
                              (cons 3 '(2 1))))))

スデにこの時点で結果が読めるので違うナニで再度手動 reduce してみます。

(scramble-b '(1 1 1 3 4 2 1 1 9 2) '())

ええと一周目。

(cons (pick 1 (cons 1 '()))
      (scramble-b '(1 1 3 4 2 1 1 9 2) (cons 1 '())))

二周目。

(cons 1
      (cons (pick 1 (cons 1 '(1)))
            (scramble-b '(1 3 4 2 1 1 9 2) (cons 1 '(1)))))

大丈夫かな。三周目。

(cons 1
      (cons 1
            (cons (pick 1 (cons 1 '(1 1)))
                  (scramble-b '(3 4 2 1 1 9 2) (cons 1 '(1 1))))))

四周目。

(cons 1
      (cons 1
            (cons 1
                  (cons (pick 3 (cons 3 '(1 1 1)))
                        (scramble-b '(4 2 1 1 9 2) (cons 3 '(1 1 1)))))))

五周目。

(cons 1
      (cons 1
            (cons 1
                  (cons 1
                        (cons (pick 4 (cons 4 '(3 1 1 1)))
                              (scramble-b '(2 1 1 9 2) (cons 4 '(3 1 1 1))))))))

六周目。ちょっと短くしてみます。

(1 1 1 1 1 (cons (pick 2 (cons 2 '(4 3 1 1 1)))
                 (scramble-b '(1 1 9 2) (cons 2 '(4 3 1 1 1)))))

七周目。

(1 1 1 1 1 (cons 4
                 (cons (pick 1 (cons 1 '(2 4 3 1 1 1)))
                       (scramble-b '(1 9 2) (cons 1 '(2 4 3 1 1 1))))))

八周目。

(1 1 1 1 1 4 (cons 1
                   (cons (pick 1 (cons 1 '(1 2 4 3 1 1 1)))
                         (scramble-b '(9 2) (cons 1 '(1 2 4 3 1 1 1))))))

九周目。

(1 1 1 1 1 4 1 (cons 1
                     (cons (pick 9 (cons 9 '(1 1 2 4 3 1 1 1)))
                           (scramble-b '(2) (cons 9 '(1 1 2 4 3 1 1 1))))))

そろそろ終わってくれ。

(1 1 1 1 1 4 1 1 (cons 1
                       (cons (pick 2 (cons 2 '(9 1 1 2 4 3 1 1 1)))
                             (scramble-b '() (cons 2 '(9 1 1 2 4 3 1 1 1))))))

ええと

(pick 2 '(2 9 1 1 2 4 3 1 1 1))

は 9 を戻すし

(scramble-b '() (cons 2 '(9 1 1 2 4 3 1 1 1)))

は '() を戻すので最終的に

'(1 1 1 1 1 4 1 1 1 9)

が戻るのか。確かに scramble は変だ。リスト遊びてきに妙なカンジ。