Go to the first, previous, next, last section, table of contents.

簡単な関数を書く

多くの正方形や円の面積を計算する場合、それ用の(Lisp)関数を持つことが助けになり ます。以下のように使うことのできる square と circle という名前の関数があれば便 利でしょう。

      (square 10)
      => 100
      (square (+ 3 4))
      => 49
      (circle 10)
      => 300

関数 square は (辺の長さを示す)アーギュメントを1つ取り、その長さの辺を持つ正方 形の面積を返します。関数 circle は (半径の長さを示す)アーギュメントを1つ取り、 円の面積を返します。

Emacs Lisp に、関数 square や circle はありませんが、それらを作ることはできる ようになっています。関数を作ることを(関数を)定義すると呼びます。このためには Lisp の defun というものを用います。以下に新しい関数 square の定義を示します。

      (defun square (length)
        (* length length))
      => square

square に対するアーギュメントが何になるかはわからないため (常に 10 であるわけ ではないことは確かですが)、それについて語るにはそれ用の名前が必要です。 Lisp ではこのために変数を用います。どのような名前でもかまわないのですが、ここではそ の変数は length と呼ばれています。関数のアーギュメントに用いられる変数は、その 関数のパラメタと呼ばれます。defun では、パラメタは(常に)関数名に続く括弧の中に 現われます (パラメタを必要としない関数も存在しますが、それらに対しては、間に変 数を書かずに括弧の対のみを書かなくてはいけません)。

関数が呼ばれると、パラメタ変数は let の変数のようにローカルバインディングを得 ます。それらはまた、(関数へのアーギュメントである)ローカル値も受け取ります。こ のように、square が呼ばれると、変数 length はローカルバインディングを得、その ローカル値は 2乗を行なう数になります。

(* length length) は、この関数が行なう計算です。このような計算を関数の本体(訳 注: body)と呼びます (let の本体について語ることもできます)。関数の返す値は常 に、本体の評価結果になります。

最初の例 ((square 10))において、パラメタ length は値 10 にバインドされます。関 数 square の本体で、length は 2 乗され、square は値 100 を返します。

2番目の例 ((square (+ 3 4)))では、異なるアーギュメントに対し(全く)同じことを行 ないます。最初に Lisp はアーギュメント (+ 3 4) を評価し 7 を得、この値で関数 square を呼びます(関数 square が (+ 3 4) というアーギュメントを "見る" ことは

ありません。それを評価した結果を "見る" だけです)。パラメタ length は 7 にバイ ンドされ、この関数の本体である ((* length length)) がこのバインディング中で評 価され、値 49 を返します。

関数 circle も(全く)同じで、私達はそのアーギュメント(半径)と、そこで用いる公式 (3 かける半径の 2乗)を知っています。この関数は以下のように書くことができます。

      (defun circle (radius)
        (* 3 (* radius radius)))
      => circle

試してみて下さい。

      (circle 10)
      => 300
      (circle (+ 3 4))
      => 147

circle の本体では radius をそれ自身に掛けます。radius を 2乗します。すでに、数 の 2乗を行なう関数 square を持っているため、 (そうしたいと思えば) circle を定 義するのにそれを用いることもできます。

square を用いて circle を定義する方法を示します。

      (defun (circle (radius)
        (* 3 (square radius)))
      => circle
      (circle 10)
      => 300
      (circle (+ 3 4))
      => 147

どちらの方がドキュメントとして良いでしょうか? どちらのほうがより明確で、より 書きやすいでしょうか? この他にも (どっちがより速いか、より費用を要するかと いった) 後で考慮しなくてはいけない点がいくつかあります。しかし、今の所は明確な ものを書くことが一番大切です。

circle のパラメタは radius で、square のパラメタは length です。このパラメタに 別の名前を用いた場合、何か違いが生ずるでしょうか? 両方のパラメタに同じ名前を 用いたらどうでしょう?

違いは生じません。関数は(その関数に対する) パラメタの値に関し、その関数固有の 考えを持っており、それが別の関数に影響を及ぼすことはありません。これは let 文 でバインドされた変数が同じ名前を持つ他の変数から守られているのと同じことです。 関数は(それぞれ)その上で処理を行なう "その関数用の紙" を持っています。

以下の 2つの関数は、互いにパラメタ名 x を用いるよう再定義されています。この変 更は、この関数が行なうことに関し、何も影響は及ぼしません。

      (defun circle (x)
        (* 3 (square x)))
      => circle
      (defun square (x)
        (* x x))
      => square
      (square 10)
      => 100
      (circle 10)
      => 300

Go to the first, previous, next, last section, table of contents.