結城浩のSICP日記 RSSフィード

2006-05-01

[]構文定義 構文定義 - 結城浩のSICP日記 を含むブックマーク

R5RSの「構文定義」は後で読みます。

define define - 結城浩のSICP日記 を含むブックマーク

R5RSの「定義」を読んでいます。ドットを使うとリストを取るのに使える。

(define (first-a x) (car x))
;=> first-a

(define first-b (lambda (x) (car x)))
;=> first-b

(define (hello-a . x) (cons "Hello" x))
;=> hello-a

(define hello-b (lambda x (cons "Hello" x)))
;=> hello-b

(first-a '(1 2 3))
;=> 1

(first-b '(1 2 3))
;=> 1

(hello-a 1 2 3)
;=> (Hello 1 2 3)

(hello-b 1 2 3)
;=> (Hello 1 2 3)

[]マクロ マクロ - 結城浩のSICP日記 を含むブックマーク

R5RSの「マクロ」は後で読みます。

[]delay delay - 結城浩のSICP日記 を含むブックマーク

R5RSの「遅延評価」を読んでいます。

delayが来ました。プロミスを返します。

(define x (delay 123))
;=> x

x
;=> #<promise 00BF1750>

(force x)
;=> 123

詳しい遅延評価は後でまたじっくり。

do do - 結城浩のSICP日記 を含むブックマーク

R5RSの「繰り返し」を読んでいます。

手続きdoはなんだか面倒くさいです。

(do ((i 0 (+ i 1))
     (sum 0 (+ sum i)))
    ((= i 10) sum)
    (print i))
0
1
2
3
4
5
6
7
8
9
;=> 45

↓のほうがわかりやすい。

(define (sum n)
  (define (sum-iterator acc i)
    (if (= i 0) acc (sum-iterator (+ i acc) (- i 1))))
  (sum-iterator 0 n))
;=> sum

(sum 9)
;=> 45

letとlet* letとlet* - 結城浩のSICP日記 を含むブックマーク

R5RSの「バインディング構成手続き」を読んでいます。

let*では、左で束縛した変数がすぐ使えます。letではだめ。

(define x 1000)
;=> x

(define (distance x y) (sqrt (+ (* x x) (* y y))))
;=> distance

(let ((x 3) (y 4)) (distance x y))
;=> 5.0

(let ((x 3) (y (+ x 1))) (distance x y))
;=> 1001.0044954944009 (xとして外側の1000が使われてしまった)

(let* ((x 3) (y (+ x 1))) (distance x y))
;=> 5.0

set!とdefine set!とdefine - 結城浩のSICP日記 を含むブックマーク

R5RSの「割り当て」を読んでいます。

set!とdefineの違いは何なのか、よくわかりませんでした→未定義のシンボルに対するエラーが違います。

(define x "Hello")
;=> x

x
;=> Hello

(set! x "Good")
;=> Good

x
;=> Good

未定義シンボルにset!を行うとエラーになります。

(set! xxx 123)
*** ERROR: symbol not defined: #<identifier user#xxx>
Stack Trace:
_______________________________________
  0  xxx

  1  xxx


(define xxx 123)
;=> xxx

(set! xxx 456)
;=> 456

任意個引数のlambda 任意個引数のlambda - 結城浩のSICP日記 を含むブックマーク

仮引数のところでドットを使うと「残りの実引数全部をリストで受け取る」ことができます。

(define (sum . xs)
  (define (sum-iterator acc xs)
    (if (null? xs)
        acc
        (sum-iterator (+ acc (car xs)) (cdr xs))))
  (sum-iterator 0 xs))
;=> sum

(sum 1)
;=> 1

(sum 1 2)
;=> 3

(sum 1 2 3)
;=> 6

(sum 1 2 3 4)
;=> 10

(sum 1 2 3 4 5)
;=> 15

(sum 1 2 3 4 5 6)
;=> 21

(sum 1 2 3 4 5 6 7)
;=> 28

(sum 1 2 3 4 5 6 7 8)
;=> 36

(sum 1 2 3 4 5 6 7 8 9)
;=> 45

…引数の受け取りはいいんだけれど、↑のプログラムはちょっといけてない。

[]()は有効な式? ()は有効な式? - 結城浩のSICP日記 を含むブックマーク

疑問:R5RSに「()は文法上有効な式ではない」と書かれている意味がよくわからない。()を評価してもエラーにならないし。

追記:ruiさんからコメントをいただきました。「Gaucheの場合は()をreadしたときに空リストを返す」ということで、処理系依存の振る舞いのようですね。後で他の処理系を試してみようかと思います。

手続き呼び出し 手続き呼び出し - 結城浩のSICP日記 を含むブックマーク

R5RS「手続き呼び出し」を読んでいます。

そうか、+や*も「そのまま」渡せるのですね。'+や'*にしなくてもよい。

(define (do-it op x y)
  (op x y))
;=> do-it

(do-it + 2 3)
;=> 5

(do-it * 2 3)
;=> 6

そ、そうか。オペランドだけではなくオペレータも同じように「評価」されているんだね。

(define use-plus #t)
;=> use-plus

((if use-plus + *) 2 3)
;=> 5

()は真 ()は真 - 結城浩のSICP日記 を含むブックマーク

#fは偽、それ以外は真。()も真。

(if #t "then" "else")
;=> then

(if #f "then" "else")
;=> else

(if () "then" "else")
;=> then

それではここでクイズです。次の式を評価したら値はthen?それともelse?

(if '#f "then" "else")

変数バインディング 変数バインディング - 結城浩のSICP日記 を含むブックマーク

R5RS「変数、構文キーワード、領域」を読んでいます。

最も内側の変数バインディングが使われるという話。

(define x 0)
;=> x

((lambda (x)
  (print x)
  ((lambda (x)
    (print x)
    ((lambda (x)
      (print x)
      (print x)) (+ x 1))
    (print x)) (+ x 10))
  (print x)) (+ x 100))
100
110
111
111
110
100
;=> #<undef>

ベクタ ベクタ - 結城浩のSICP日記 を含むブックマーク

R5RS「ベクタ」を読んでいます。

'#(3 1 4 1 5 9)
;=> #(3 1 4 1 5 9)

(define v '#(3 1 4 1 5 9))
;=> v

(vector? v)
;=> #t

(vector-length v)
;=> 6

(vector-ref v 2)
;=> 4

バッククォートとコンマ バッククォートとコンマ - 結城浩のSICP日記 を含むブックマーク

R5RS「バッククォート式」を読んでいます。

バッククォートはクォートとほぼ同じだけれど、コンマがあったらそこだけ評価して展開します。

(大昔、学生時代にLispを習ったときにはコンマってまったく理解できなかったんだけれど、いまはするっと理解できる。不思議なものだなあ…)

'(1 2 3 4 5)
;=> (1 2 3 4 5)

`(1 2 3 4 5)
;=> (1 2 3 4 5)

`(1 2 3 4 ,(+ 2 3))
;=> (1 2 3 4 5)

と思ったら、ネストしたときはちょっとやっかい。一番外側のquasiquote (`)と一番内側のunquote (,)が対応している。

'(1 2 '(3 4 5))
;=> (1 2 '(3 4 5))

`(1 2 `(3 4 5))
;=> (1 2 `(3 4 5))

`(1 2 `(3 ,(+ 2 2) ,(+ 2 ,(+ 2 1))))
;=> (1 2 `(3 ,(+ 2 2) ,(+ 2 3)))

識別子 識別子 - 結城浩のSICP日記 を含むブックマーク

R5RS「識別子」を読んでいます。Schemeの識別子には記号(! $ % & * + - . / : < = > ? @ ^ _ ~)も使えるようです。

(define (+++ x) (+ x 2))
;=> +++

(+++ 4)
;=> 6

MITのオープンコース MITのオープンコース - 結城浩のSICP日記 を含むブックマーク

MIT OpenCourseWare6.001 Structure and Interpretation of Computer Programs, Spring 2005という講座があり、オンラインで閲覧できるようです。(via id:naoya_t about)

自動読み込みの方法 自動読み込みの方法 - 結城浩のSICP日記 を含むブックマーク

以下の定義をgosh起動時に自動的に読ませるにはどうしたらよいだろうか。(ちょうど.bashrcのように)

;read-eval-print.scm
(read-eval-print-loop
  #f #f
  (lambda args
    (for-each
      (lambda (expr) (print ";=> " expr))
      args))
  (lambda () (newline)))

Gaucheのリファレンスマニュアル「3.1 Gaucheを起動する」を読んで解決。

コマンドラインオプションで-lを指定すると自動的に読み込まれる。ロードパスを指定するオプション-Aも合わせて指定する。

gosh -A . -l read-eval-print.scm

ついでに、gaucheでは--helpオプションではusageが表示されない。invalidなオプション(たとえば-h)を指定する。

> gosh -h
gosh: unknown option -- h
Usage: gosh [-biqV][-I<path>][-A<path>][-u<module>][-l<file>][-e<expr>][--] [file]
options:
  -V       Prints version and exits.
  -b       Batch mode.  Doesn't print prompts.  Supersedes -i.
  -i       Interactive mode.  Forces to print prompts.
  -q       Doesn't read the default initialization file.
  -I<path> Adds <path> to the head of the load path list.
  -A<path> Adds <path> to the tail of the load path list.
  -u<module> (use) load and import <module>
  -l<file> Loads <file> before executing the script file or
           entering repl.
  -e<expr> Evaluate Scheme expression <expr> before executing
           the script file or entering repl.
  -E<expr> Similar to -e, but reads <expr> as if it is surrounded
           by parenthesis.
  -p<type> Turn on the profiler.  Currently <type> can only be
           'time'.
  -f<flag> Sets various flags
      case-fold       uses case-insensitive reader (as in R5RS)
      load-verbose    report while loading files
      no-inline       don't inline procedures & constants (combined
                      no-inline-globals, no-inline-locals, and
                      no-inline-constants.
      no-inline-globals don't inline global procedures.
      no-inline-locals  don't inline local procedures.
      no-inline-constants don't inline constants.
      no-source-info  don't preserve source information for debug
      test            test mode, to run gosh inside the build tree

lambda lambda - 結城浩のSICP日記 を含むブックマーク

(lambda ...)というものについて。

1
;=> 1

(+ 3 1)
;=> 4

lambda
;=> #<syntax lambda>

(lambda (x) (+ x 1))
;=> #<closure #f>

((lambda (x) (+ x 1)) 3)
;=> 4

(define (add-one-a x) (+ x 1))
;=> add-one-a

(add-one-a 3)
;=> 4

(define add-one-b (lambda (x) (+ x 1)))
;=> add-one-b

(add-one-b 3)
;=> 4

add-one-a
;=> #<closure add-one-a>

add-one-b
;=> #<closure add-one-b>

なるほど。

syntax syntax - 結城浩のSICP日記 を含むブックマーク

3.5をぱらぱら見ていて、delayは特殊形式と出てきた。それはそうだ。ふとプロンプトでdelayと入れたら#<syntax delay>と表示された。他にはどんなものがあるかを想像しながらキー入力した。

gosh> delay
#<syntax delay>
gosh> define
#<syntax define>
gosh> quote
#<syntax quote>
gosh> lambda
#<syntax lambda>
gosh> set!
#<syntax set!>

procedure? procedure? - 結城浩のSICP日記 を含むブックマーク

procedure?を使うと、手続きかどうかを調べることができます。

gosh> (procedure? procedure?)
#t
gosh> (procedure? 'procedure?)
#f
gosh> (procedure? 'car)
#f
gosh> (procedure? (lambda (x) (car x)))
#t
gosh> (procedure? '(lambda (x) (car x)))
#f

R5RSを読む準備(CSS) R5RSを読む準備(CSS) - 結城浩のSICP日記 を含むブックマーク

プログラミング言語Schemeのページ経由で、R5RSの原文と犬飼さんの翻訳がダウンロードできます。ありがたい。ところでこのHTMLはtexi2htmlで出力させたもので、いささか読みにくい。そこで以下のようなスタイルシートを書き、HTMLから読み込ませるようにしました。

/* style.css */
body {
    font-family: Verdana; /* experimental */
    margin-right: 8%;
    margin-left: 8%;
    background-color: white;
    color: black;
}
h1, h2, h3 {
    margin-top: 3em;
    padding: .5ex .5ex .5ex .5ex;
    font-weight: normal;
}
h2 {
    border-bottom: gray 3px double;
}
h3 {
    border-bottom: gray 1px solid;
}
pre {
    background-color: #eeeeff;
    color: black;
    padding: 1em;
    border: 1px dotted #ccccff;
}
i {
    font-style: normal;
    font-weight: bold;
    color: #009999;
}
em {
    font-style: normal;
    font-weight: bold;
    color: #0000cc;
}

以下がHTML(たとえばr5rsj.html)の書き換え場所。metaタグとlinkタグを入れた。DOCTYPEなどもちゃんとやればよいのですが省略。

<HTML>
<HEAD>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-JP" />
<link href="style.css" type="text/css" rel="stylesheet" />
<!-- Created by texi2html 1.57 from r5rsj.texi on January, 22  2000 -->

これだけで、HTMLがとても読みやすくなります。

方針を考える 方針を考える - 結城浩のSICP日記 を含むブックマーク

SICPを読むということで、日記を立てるためのグループを作り、少し動いてみました。

でもやってみると、そこはかとなく飽きそうな予感がしています:-) なぜかというと、問題はやっぱりSICPを「読む」というところにあるようです。

そこで今後の方針としては、SICPを順番に読むことにはこだわらず、Schemeを勉強したり・SICPを読んだりという感じで進もうかなと思っています。

とはいえ何らかの征服感はほしいので(贅沢ですね)、SICPで読んだり考えたりした部分のセクション番号やページ番号は記録していくつもりです。

いま気になっているのは、R5RSです。これにさくさくっと目を通しておいたほうが今後の勉強が楽になるのではないかな、と想像中。

ruirui2006/05/01 17:18> 疑問:R5RSに「()は文法上有効な式ではない」と書かれている意味がよくわからない。
R5RSで規定されていない範囲の動作や、エラーの場合の動作は、処理系の裁量にまかされています。()をreadしたときに、エラーをユーザに通知する代わりに、それなりに動作する(この場合は空リストを返す)のも問題ない動作だということになります。Gaucheは()をreadしたときに空リストを返します。
処理系の間での移植性を高めるために、'()と書いておくほうがいいとは思いますが。