Common Lispでグローバル関数を定義するには、defun式を使います。
この式は、最初の引数として仮引数のリストを取ります(空のリストなら、その関数は引数を取らないという意味です)。
続いて省略可能なドキュメンテーション文字列(後述します)を書き、そのあとに0個以上の式を書きます。この式たちが関数の「本体」になります。
関数は、0個以上の仮引数を持てます。
(defun no-args () (+ 1 1))
(defun add-one (x) (1+ x))
(defun add-nums (x y) (+ x y))
関数を呼び出すには、その関数を表すシンボルを式の最初の要素にし、関数への引数(あれば)を残りの要素にした式を評価します。
関数が評価した結果の値は、関数の本体の中で最後に評価された式の値です。 すべての関数は、何らかの値に評価されます。
(add-nums 2 2) ;; => 4
関数には、省略可能で、ドキュメンテーション文字列(docstringとも呼びます)を持たせることもできます。
書く場合は、引数リストのあと、関数の本体の前に置きます。
ドキュメンテーション文字列には、documentationでアクセスできます。
(defun add-nums (x y) "Add X and Y together" (+ x y))
(documentation 'add-nums 'function) ;; => "Add X and Y together"
;; Note that if one provides a docstring but fails to provide a body
;; then the docstring is interpreted by Common Lisp as the body, not
;; the docstring
(defun no-body ())
(no-body) ;; => NIL
(defun mistake () "This is not a docstring")
(mistake) ;; => "This is not a docstring"
(documentation 'mistake 'function) ;; => NIL
Lisp AlienのLillyが戻ってきて、また料理をしています! 今度は、人間のラザニアとそれほど変わらない「Lisp Alienラザニア」を作ろうとしています。
Lillyは、ラザニアを焼く時間を計算するための関数をいくつか書く必要があります。しかも、それぞれの関数が何をするのか忘れないように、きちんとドキュメントを付けておく必要があります。
Lillyがラザニアの調理時間を計れるように、関数を書くのを手伝ってあげませんか?
入力を受け取らず、ラザニアをオーブンに入れておくべき時間を分で返すexpected-time-in-oven関数を定義します。Lisp Alienの伝統(Lillyの親ユニットも同じように料理していました)によると、オーブンに入れておくべき時間は337分です。
(expected-time-in-oven) ;; => 337
remaining-minutes-in-oven関数を定義します。この関数は、ラザニアがすでにオーブンに入っていた実際の分数を入力として受け取り、前のタスクで定義したオーブンに入れておくべき時間(分)をもとに、あと何分オーブンに入れておく必要があるかを返します。
(remaining-minutes-in-oven 100) ;; => 237
preparation-time-in-minutes関数を定義します。この関数は、Lillyがラザニアに重ねた層の枚数を入力として受け取り、1枚あたり19分かかるものとして、ラザニアの準備に何分かかったかを返します。
(preparation-time-in-minutes 3) ;; => 57
elapsed-time-in-minutes関数を定義します。この関数は2つの入力を受け取ります。1つ目はLillyがラザニアに重ねた層の枚数、2つ目はラザニアがオーブンに入っていた分数です。この関数は、ラザニアの調理にLillyがこれまで取り組んだ時間を分で返します。これは、準備時間(分)と、その時点でラザニアがオーブンに入っていた時間(分)の合計です。
(elapsed-time-in-minutes 3 100) ;; => 157
Exercismに登録すれば、27個のコンセプト92個の演習、そして本物の人間によるメンタリングとともに、Common Lispを学んでマスターできます。すべて無料です。