Next: Calling Functions, Previous: Function Names, Up: Functions [Contents][Index]
わたしたちは通常は関数を最初に作成したときに名前を与えます。これは関数の定義(defining a
function)と呼ばれ、defunマクロにより行われます。
defunは新たなLisp関数を定義する通常の方法である。これは引数リストargs、およびbodyにより与えられるbodyフォームとともに、シンボルnameを関数として定義する。nameとargsをクォートする必要はない。
docが与えられたら、それはその関数のドキュメント文字列を指定する文字列であること(Function Documentationを参照)。declareが与えられたら、それは関数のメタデータを指定するdeclareフォームであること(Declare Formを参照)。interactiveが与えられたら、それは関数が対話的に呼び出される方法を指定するinteractiveフォームであるこ(Interactive Callを参照)。
defunのリターン値は定義されていません。
以下にいくつか例を示す:
(defun foo () 5)
(foo)
⇒ 5
(defun bar (a &optional b &rest c)
(list a b c))
(bar 1 2 3 4 5)
⇒ (1 2 (3 4 5))
(bar 1)
⇒ (1 nil nil)
(bar) error→ Wrong number of arguments.
(defun capitalize-backwards () "Upcase the last letter of the word at point." (interactive) (backward-word 1) (forward-word 1) (backward-char 1) (capitalize-word 1))
意図せず既存の関数を再定義しないように注意されたい。defunはcarのようなプリミティブ関数でさえ、問い合わせせずに躊躇なく再定義する。Emacsがこれを妨げることはない。なぜなら関数の再定義は故意に行われることがあり、そのような意図した再定義を、意図しない再定義と見分ける方法はがないからである。
この関数は定義definition(任意の有効なLisp関数)とともに、シンボルnameを関数として定義する。この関数のリターン値は未定義。
docが非nilなら、それは関数nameのドキュメントとなる。それ以外ならdefinitionにより提供されるドキュメントが使用される。
内部的にはdefaliasは、通常は定義のセットにfsetを使用する。しかしnameがdefalias-fset-functionプロパティーをもつなら、fsetを呼び出すかわりにそれに割り当てられた値を使用する。
defaliasを使う正しい場所は、特定の関数名が正に定義される場所 —
特にソースファイルがロードされるとき明示的にその名前が出現する場所である。これはdefaliasがdefunと同じように、どれが関数を定義するファイルなのか記録するからである(Unloadingを参照)。
それとは対象的に他の目的のために関数を操作するプログラムでは、そのような記録を保持しないfsetを使用するほうがよいだろう。Function Cellsを参照のこと。
defunやdefaliasで新たなプリミティブ関数を作成することはできませんが、任意の関数定義を変更するのに使用することができ、通常の定義がプリミティブであるcarやx-popup-menuのような関数でさえ変更することができます。しかしこれは危険なことです。たとえばLispの完全性を損なうことなく、carを再定義するのはほとんど不可能だからです。それほど有名ではないx-popup-menuのような関数の再定義では、危険は減少しますが、それでも期待したとおりに機能しないかもしれません。Cコードにそのプリミティブの呼び出しがあれば、それは直接そのプリミティブのC定義を呼び出すので、シンボル定義を変更してもそれらに影響はありません。
defsubstも参照してください。これはdefunのように関数を定義して、それのインライン展開を処理するようLispコンパイラーに指示します。Inline Functionsを参照してください。
かわりにコンパイラーマクロとしてインライン展開されるコードを記述することにより関数を定義できます。以下のマクロがこれを可能にします。
自身をインライン化するコードを提供することにより、コンパイラーマクロとして関数nameを定義する。この関数は引数リストargsを受け取り、指定されたbodyをもつ。
docが与えられたなら、それは関数のドキュメント文字列であること(Function Documentationを参照)。declareが与えられたなら、それは関数のメタデータを指定するdeclareフォームであること(Declare Formを参照)。
define-inlineで定義された関数は、defsubstやdefmacroで定義されたマクロにたいして複数の利点をもちます。
mapcarに渡すことができる(Mapping Functionsを参照)。
cl-defsubstより予測可能な方法で振る舞う(Argument Lists in Common Lisp
Extensions for GNU Emacs Lispを参照)。
defmacroと同様に、define-inlineでインライン化された関数は、呼び出し側からダイナミックかレキシカルいずれかのスコーピングルールを継承します。Variable Scopingを参照してください。
以下のマクロはdefine-inlineで定義された関数のbody内で使用する必要があります。
define-inlineにたいしてexpressionをクォートする。これはバッククォート(Backquoteを参照)と似ているが、コードをクォートして,だけを受け入れ、,@は受け入れない。
これはlet (Local Variablesを参照)と似ているが、bindingsで指定されたようにローカル変数をセットアップして、そのバインディングの効力の下でbodyを評価する。bindingsのそれぞれの要素はシンボルか(var expr)という形式のリストのいずれかであること。後者ならexprを評価した結果がvarにバインドされる。bindingsの末尾にはnil、または引数のリストを保持するシンボルを指定できる。後者の場合は各引数が評価されて、そのシンボルに結果リストがバインドされる。
expressionの値が既知なら非nilをリターンする。
expressionの値をリターンする。
formatに応じてargsをフォーマットしてエラーをシグナルする。
以下はdefine-inlineを使用した例です:
(define-inline myaccessor (obj)
(inline-letevals (obj)
(inline-quote (if (foo-p ,obj) (aref (cdr ,obj) 3) (aref ,obj 2)))))
これは以下と等価です
(defsubst myaccessor (obj) (if (foo-p obj) (aref (cdr obj) 3) (aref obj 2)))
Next: Calling Functions, Previous: Function Names, Up: Functions [Contents][Index]