これは良い質問で、Common Lisp がかなり混乱する可能性がある質問です。問題は、歴史的な理由から、Common Lisp には 2 つの名前空間があります。1 つは関数用で、もう 1 つは値用です。これを実現するために、関数適用の先頭位置とそれ以外の評価規則が 2 つあります。1 つ目はシンボルを関数名として評価し、2 つ目はシンボルを変数参照として評価します。明らかに、値が実際に関数である場合があります。たとえば、mapcar
関数を作成する場合は、次のようにします。
(defun my-mapcar (f l)
(if (null l)
'()
(cons (f (car l)) (my-mapcar f (cdr l)))))
しかし、これは機能しませんf
。不明な関数であると文句を言うでしょう。このような場合のためにfuncall
、 と呼ばれる特別な関数があり、関数と関数の引数を受け取り、通常どおり関数を適用します。funcall
は単純な関数であるため、その引数はすべて通常どおり (値として) 評価されます。したがって、上記はそれを使用して修正する必要があります。
(defun my-mapcar (f l)
(if (null l)
'()
(cons (funcall f (car l)) (my-mapcar f (cdr l)))))
あなたがおそらく今疑っているように、何かを値としてではなく関数として評価したいというミラーケースがあります。たとえば、これは機能しません。
(my-mapcar 1+ '(1 2 3))
1+
関数ではなく変数を参照するためです。これらの場合のために、function
その内容を関数として評価し、値として返す特別なフォームが呼び出されます。
(my-mapcar (function 1+) '(1 2 3))
と省略できます#'
。
(my-mapcar #'1+ '(1 2 3))
この話はこれで終わりではありません。例をいくつか挙げます。
場合によっては、引用符で囲まれた単純な名前が関数として機能する'1+
ことがあり#'
ます。
同様のハックを使用できますlambda
-- したがって、使用できます(my-mapcar '(lambda (x) (1+ x)) '(1 2 3))
。実際、(list 'lambda '(x) '(1+ x))
これはさらに悪い (そして IIRC、非移植性) を使用できますが、使用は(lambda (x) (1+ x))
暗黙的に a でラップされているため機能します(フォームをマクロとして#'
展開してみてください) 。lambda
そして、あなたはそれを見るでしょう)。関連するハックにより、lambda
式を関数アプリケーションの先頭として使用することができます (これは、あなたが試したことの 1 つです)。
let
などはローカル値をバインドします。場合によっては、代わりにローカル関数をバインドする必要があります。このために、新しいバインド構造がありますflet
。labels
これらすべてが奇妙に見えたり、過度に複雑に見えたりする場合、それはあなただけではありません。Common Lisp と Scheme の主な違いの 1 つです。(この違いは、両方の言語で共通のイディオムの変更につながります。Scheme コードは、Common Lisp コードよりもはるかに頻繁に高階関数を使用する傾向があります。この種の宗教的な質問でいつものように、一部の人々は、CL が行うことを支持して主張し、次のように主張します。高階関数は紛らわしいので、明示的なコード内リマインダーが好きです。)