独習 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 はスルーします。午後からは大掃除。