独習 scheme 三週間 (2)

昨日さっそくサボッてしまった。

Chapter.3

フォーム

lambda と言えば随分前に勉強資料で使ってた文書 (出自を忘れた) にいきなりこんなの

guile> (define addx (lambda (x) (lambda (y) (+ x y))))
guile> (define add5 (addx 5))
guile> (define add4 (addx 4))
guile> (add5 5)
10
guile> (add4 5)
9
guile>

が出ててナンダコレハ、と思った記憶あり。あと lambda 式と言えば「なんでもλ」はも一度きちんと読まねば。

色々コンソール上で試験してみてて、一旦微妙な部分を列挙しときます。あ、その前にハマッたのは以下。

guile> (define p (lambda (x) ((display x) (newline))))
guile> (define a '(3 4 5))
guile> (p a)
(3 4 5)standard input:72:23: In expression ((display x) (newline)):
standard input:72:23: Wrong type to apply: #<unspecified>
ABORT: (misc-error)
guile> (define p (lambda (x) (display x) (newline)))
guile> (p a)
(3 4 5)
guile> 

何故手続き全体を括弧で囲んでしまったのかは謎ですが、あんまりコードを書いてないっつーのがもろバレだなぁ、と。
余計な話は置いといて3.1.2 可変長の引数んトコを見つつ色々試す。

guile> (define p (lambda (x) (display x) (newline)))
guile> ((lambda (x y z) (p x) (p y) (p z)) 3 4 5)
3
4
5
guile> ((lambda (x y z) (p x) (p y) (p z)) 3 4 5 6 7)
standard input:78:1: In expression ((lambda # # ...) 3 4 ...):
standard input:78:1: Wrong number of arguments to #<procedure (x y z)>
ABORT: (wrong-number-of-args)
guile>

引数の数が明示的だったらこうなるのか。シンボルいっこだとリストになって渡るようだ。

guile> ((lambda args (p args)) 3 4 5)
(3 4 5)
guile> ((lambda args (p args)) 3 4 5 6 7)
(3 4 5 6 7)
guile>

強制的にリストになってしまう、というのは scheme 的にはシアワセなんだろうな、きっと。
ではこんなのは??

guile> ((lambda args (p args)) '(3 4 5) 6 7)
((3 4 5) 6 7)
guile> ((lambda args (p args)) (3 4 5) 6 7)
standard input:82:25: In expression (3 4 5):
standard input:82:25: Wrong type to apply: (3 4 5)
ABORT: (misc-error)
guile> 

リストは quote しないと駄目っぽい。引数がペア、なナニはこんな感じ??

guile> ((lambda (x . y) (p x) (p y)) 3 4 5)
3
(4 5)
guile> ((lambda (x . y) (p x) (p y)) 3)  
3
()
guile> ((lambda (x . y) (p x) (p y)))
standard input:87:1: In expression ((lambda # # ...)):
standard input:87:1: Wrong number of arguments to #<procedure (x . y)>
ABORT: (wrong-number-of-args)
guile> ((lambda (x . y) (p x) (p y)) '())
()
()
guile> 

空のリストだと OK なのか。ペアで引数指定した場合はケツは略しても OK らしい。

次、apply。

guile> (define a (list 3 4))
guile> a
(3 4)
guile> (p a)
(3 4)
guile> (apply + 1 2 3 a)
13
guile> (apply + 1 2 3 (list 3 4))
13
guile> (define mul (lambda args (apply * args)))
guile> (mul 1 2 3)
6
guile> (mul 1 2 3 (list 4 5))
ERROR: In procedure *:
ERROR: Wrong type argument: (4 5)
ABORT: (wrong-type-arg)
guile> 

これも mul には (1 2 3) が渡ってるから微妙なコトになってるのかなぁ。てコトで mul を変更してみて試してみる。

guile> (define mul (lambda args (p args) (apply * args)))
guile> (mul 1 2 3)
(1 2 3)
6
guile> (mul 1 2 3 (list 4 5))
(1 2 3 (4 5))
ERROR: In procedure *:
ERROR: Wrong type argument: (4 5)
ABORT: (wrong-type-arg)
guile> 

成程。

で、最後の直列化の項を見て、最初のエラーのナニが判明。begin で囲めば良かったのね。フォームとゆーか S 式の評価についての理解が足りてないんでしょうな。ってか慣れてないだけなのかなぁ。(とほほ
以下、p を begin を使って定義してみた例。(蛇足

guile> (define p (lambda (x) (begin (display x) (newline))))
guile> (define a (list 3 4))
guile> a
(3 4)
guile> (p a)
(3 4)
guile> 

Chapter.4 は略。

Chapter.5

レキシカル変数

コンテンツのファイル名に 7 が付いてるってコトは 7 日目とゆー事かなぁ。(違
このあたりからじっくり見てみた方が良さげ。いきなり_レキシカルスコープ_という用語が出てくるな。随分前に Lisp/scheme を自習した時に、これらの用語にとても惑わされた記憶あり。クロージャとかその他モロモロ。とりあえず変数名で領域を参照する時のルールとしては C なんかと同じ、とゆー理解で。

ここでまずハマッたのが let です。括弧がニ個必要なのね、みたいな。(駄目
とりあえずクラスってかオブジェクトみたいのを作ってみっか、と思い以下の間違い。

guile> (define make-counter (lambda (c) (let (cnt c) (lambda () (set! cnt (+ cnt 1)) cnt))))
guile> (define xxx-cnt (make-counter 0))
standard input:141:17: In procedure let in expression (make-counter 0):
standard input:141:17: bad bindings
ABORT: (misc-error)
guile> 

エラーメセジとして非常に不親切。(を

それは良いとして以下のような感じで非常にお手軽。

guile> (define make-counter (lambda (c) (let ((cnt c)) (lambda () (set! cnt (+ cnt 1)) cnt))))
guile> (define no1-ctr (make-counter 0))
guile> (no1-ctr)
1
guile> (no1-ctr)
2
guile> (define no2-ctr (make-counter 0))
guile> (no2-ctr)
1
guile> (no1-ctr)
3

let 使わねぇで以下のような書き方もできるみたい。

guile> (define (make-counter2 cnt) (lambda () (set! cnt (+ cnt 1)) cnt))
guile> (define no3-ctr (make-counter2 0))
guile> (no3-ctr)
1
guile>

R5RS 見てみると 7.1.6 節に記述あり。と、ゆー事はこんなのもあり、か。

guile> (define (aaa x y z) (p x)(p y)(p z))
guile> (aaa 1 2 3)
1
2
3
guile> 

以下の定義と等価と見てよいよな。

guile> (define bbb (lambda (x y z) (p x)(p y)(p z)))
guile> (bbb 1 2 3)
1
2
3
guile> 

間違えてこんな事しちゃってます (恥

guile> (define (aaa x y z) (lambda () (p x)(p y)(p z)))
guile> (aaa 1 2 3)
#<procedure ()>
guile> ((aaa 1 2 3))
1
2
3
guile>

あ、てコトは p はこんな書き方もできるんか。

guile> (define (p x) (display x) (newline))
guile> (define a (list 1 2 3))
guile> a
(1 2 3)
guile> (p a)
(1 2 3)
guile> 

こっちの方が lambda って入力しなくて良いから楽ちん、なのかなぁ??

む。let と let* の違いも明快に記述されてるな (letとlet*)。

guile> (define x 20)
guile> (let ((x 1) (y 2) (z 3)) (list x y z))
(1 2 3)
guile> x
20
guile>

let ん中の x はローカルスコープって事で。

guile> (let ((x 1) (y x)) (+ x y))
21
guile>

上記のケースでは y に設定されている x はグローバルスコープな x ですか。で、これをナニしたい場合には let* を使う、と。

guile> (let* ((x 1) (y x)) (+ x y))
2
guile>

この書き方は下記のケースと等価、とある。

guile> (let ((x 1)) (let ((y x)) (+ x y)))
2
guile>

fluid-let はスルーします。午後からは大掃除。