[ 目次, 前節, 次節, 索引 ]

1.1.4 合成手続き



強力なプログラム言語に備わっているべき要素がLispにもあることを見てきた.

• 数と算術演算子は基本的データと手続きである.

• 組合せの入れ子は演算を組み合せる手段である.

• 名前と値を対応づける定義は抽象のそこそこの手段である.

さらに強力な抽象化技法である 手続き定義(procedure definitions)を学ぼう. これにより, 合成演算に名前を対応づけ, 一体として指すことが出来る.

   手始めに「二乗」の表し方を調べる. 「何かを二乗するには, それにそれ自身を掛ける」というであろう. われわれの言語では, 次のように表す.


(define (square x) (* x x))

   これは次のように理解することが出来る.

(define (square   x)      (*    x       x))
↑       ↑       ↑      ↑    ↑      ↑
には     二乗する 何かを, 掛ける それに それ自身を.

これでsquareという名前の 合成手続き(compound procedure)が出来た. この手続きは何かにそれ自身を掛ける演算を表す. 掛けられるものは局所的な名前xを持つ. これは自然言語の代名詞のように働く. 定義を評価すると, この合成手続きが作られ, squareという名前が対応づけられる.12

   手続き定義の一般的形は:

(define (⟨name⟩ ⟨formal parameters⟩) ⟨body⟩)
である. 名前⟨name⟩は, 環境でこの手続き定義に対応づける名前である.13 仮パラメタ⟨formal parameters⟩は, 手続き本体の中で, 手続きの対応する引数を指すための名前である. 本体⟨body⟩は, 仮パラメタが, 手続きを作用させる実引数で取り替えられて手続き作用の値を計算する式である.14name⟩と⟨formal parameters⟩は, かっこの中にまとめられ, この手続きを実際に呼び出す時と同じ形をしている.

   squareが定義出来たので, 使うことが出来る:

(square 21)
441

(square (+ 2 5))
49

(square (square 3))
81

   squareを他の手続きを定義する組立て素材に使うことも出来る. 例えば, x2 + y2

(+ (square x) (square y))
のように表せる. 引数として二つの数値をとり, それらの二乗の和を作る手続きsum-of-squaresを定義するのも容易である.

(define (sum-of-squares x y)
  (+ (square x) (square y)))

(sum-of-squares 3 4)
25
sum-of-squaresを別の手続きを作る組立て素材とすることも出来る.
(define (f a)
  (sum-of-squares (+ a 1) (* a 2)))

(f 5)
136
合成手続きは基本的手続きとまったく同様に使うことが出来る. 実際, 上のsum-of-squaresの定義を見ただけでは, square+ *のように解釈系に作り込まれたか, 合成手続きとして定義されたか分らない.


12 ここでは二つの演算が合成されていることに注意しよう: 手続きを作り出し, それにsquareという名前をつけた. この二つの考え方--- 名前をつけずに手続きを作り出すことと,すでに作り出されている手続きに名前をつけること---を分離することが出来, しかも重要である. このやり方は1.3.2節で学ぶ.

13 本書では, 「スロット」を示す式の一般的構文に, ---例えば⟨name⟩のように---角かっこで区切られた斜体記号を使い, それは式が実際に使われる時に挿入される.

14 より一般的には, 手続きの本体は 式の並びでよい. そういう場合, 解釈系は並びの中の式を順に評価し, 最後の式の値を手続き作用の値として返す.

[ 目次, 前節, 次節, 索引 ]