• 検索結果がありません。

3. その結果を表示する

3.8 手続き

> (eq? (list 'pooh 'piglet) (list 'pooh 'piglet))

#f

> (define animal (list 'pooh 'piglet))

#<unspecified>

> (eqv? animal animal)

#t

> (eq? '() '())

#t

手続きequal? は、対やベクトルなどの比較のときには、要素それぞれを比較しますが 、

さらに対やベクトルがあればそれらの要素についても、さらに等しいかど うかを調べます。

(

ベクトルは、

6.1.2

にて学びます。

)

その他

(

数や記号など

)

に対しては、eqv?と同じ方法

で同じかど うかを調べます。

(

直観的な説明ですが 、

2

つのデータが同じに表示されるとき は、equal? は #tを返す場合が多いです。

)

> (equal? '(a b) '(a b))

#t

> (equal? (list 'a 'b) (list 'a 'b))

#t

> (equal? '(a b (c d)) '(a b (c d)))

#t

> (equal? "my home" "my home")

#t

> (equal? 13 13)

#t

> (equal? 3.14 3.14)

#t

> (equal? 1 1.0)

#f

の例では引数に

1

を加えた数を返す手続き add1を定義しています。

> (define (add1 n) (+ n 1))

#<unspecified>

|

defineが返す値

> (add1 1) 2

> (add1 99) 100

手続き呼び出しで与えられた

ひきすう

引数 のことを、

じつひきすう

実引数

(actual argument)

といいます。上

での (add1 1) の場合だと 1が実引数です。手続き add1 の定義の中での nは、add1が 呼び出されたときの実引数の値が入れられ 、add1の本体部分である (+ n 1) が実行され ます。nは手続きadd1の

かりひきすう

仮引数

(formal argument)

と呼ばれます。

nが実引数の値を持つのは、手続き add1の内部だけです。add1 の外で nが値を持って いてもadd1の中では実引数の値が優先され 、外での n の値は隠されてます。nが実引数 の値を持つのは手続き add1の内部だけで、add1 の実行が終了したら元の値に戻ります。

> (define n 10)

#<unspecified>

> n 10

> (add1 1) 2

> n 10

この例では、まず変数n の値を 10 にしています。そして手続き add1を呼び出していま すが 、nの値を 10 にしたことは影響していません。add1 の実行が終了したのちに変数n の値を調べていますが 、add1の実行によって値が 1になっておらず、前のままの 10であ ることがわかります。

次は、

2

つの引数を持った手続きの例です。

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

#<unspecified>

> (distance 1 1) +1.414213562373095

> (distance 2 4) +4.47213595499958

一般的に手続き定義は次の形をしています。

(define (h手続き名i h仮引数のならびi)

h1i

h2i

...

h

n

i )

ここで h手続き名i は変数で 、h仮引数のならび i は変数を任意個ならべたものです。仮 引数のならびには、同じ名前の変数が現れてはいけません。

手続き呼び出しは、 一般的には次の形をしています。

(h手続き名i h実引数のならびi)

以前に出てきた変数の定義では(define count 0)という書き方をしていました。手続 き定義の場合では、定義する手続き名と仮引数が括弧で囲まれていて、同じ define なの に変数のときと使い方が違っています。上で紹介した手続き定義の方法は、実は簡略記法 です。簡略でない記法で add1の定義を書くと次のようになります。

(define add1

(lambda (n) (+ n 1)))

ここで (lambda ) は 、ラムダ式

( expression)

と呼ばれるものです。これが評価さ

れると 手続き

(procedure)

という型のデータが返されます。これでわかるように、手続き

定義は変数定義とまったく同じです。定義する変数の値が手続きデータであるというだけ です。

} (lambda h仮引数i h本体i)

|

h仮引数i をパラメータとして持ち、本体の式のならびがh本体i である手続き を作ります。

} (procedure? hデータi)

|

hデータiが手続きデータなら真#t を、そうでなければ偽 #fを返します。

ラムダ式は名前のない手続きともみなせます。たとえば与えられた数に

1

を加える手続

きは

(lambda (n) (+ n 1))

と表せます。ですので

1

を加えた数を求めるのに 、define を使って新しい手続きを定義 する必要はありません。

> ((lambda (n) (+ n 1)) 10) 11

この例ではまず(lambda (n) (+ n 1))が評価されて、「引数に

1

を加える手続きデータ」

が作られます。次に引数が評価されて 10 を得ます。最後に 10 が手続きデータに渡され て、実行されます。

こんどは次の場合を考えてみましょう。

> (add1 10) 11

この場合も上の場合と同じです。まず add1が評価されます。この変数の値は、「引数に

1

を加える手続きデータ」です。次に引数が評価されて 10 を得ます。最後に 10 が手続き データに渡されて実行されます。

手続きもひとつのデータなので 、手続きを他の手続きに引数として与えることもでき ます。

> (define (calc x op y) (op x y))

#<unspecified>

> (calc 3 + 4) 7

> (calc 2 - 8) -6

> (calc 3 * 6) 18

+

,

-

,

*はそれぞれ 、「加算をする手続き」、「減算をする手続き」、「乗算をする手続き」を 値として持っています。手続き calc の中で op は 、引数で与えられた手続きデータを値 として持っています。式(op x y)の評価は、opが値として持っている手続きデータに x と yを渡して実行するようになっていて、その結果が calc の値となっています。

これまで説明したラムダ式の引数は、(x op y)のような変数のリストで、取り得る「引 数の数」は決まっていました。そのために、式 (calc 2)を評価しようとすると、引数の 数が異なるためにエラーとなります

:

> (calc 2)

Error: Wrong number of args to ...

in excpression: (... calc 2) in top level environment.

; Evaluation took 50msec ...

たとえば足し算をする手続き+ は、任意の数の引数をとることができます。このように あるときの呼び出しでは

2

つの引数で、またあるときの呼び出しでは

4

つの引数で、とい

うように、手続き呼び出しのたびに引数の数を変える方法を紹介します。

任意の数の引数を手続きに渡すのに、(foo (list a b c d e))として引数をすべて

1

つのリスト入れるのもひとつの方法です。すると手続き fooは、

1

引数の手続きとして作

ればよいことになります。ですがいちいちリストにまとめるのも大変です。

手続きが可変数の引数を受けとるには、次のようにします。

(define h手続き名i (lambda h引数名i

h式のならび i ))

ここで h引数名iは記号のリストではなく、ひとつの記号であることに注意して下さい。

たとえば (define foo

(lambda s

(if (null? s) '()

(list-ref s (- (length s) 1)))))

は、fooの最後の引数を返す手続きです。(foo 1 2 3 4)の評価において仮引数sは、値

(1 2 3 4) を持つことになります。

> (foo 1 2) 2

> (foo 1 2 3 4 5) 5

> (foo) ()