2010-12-26 10 views
11

値のリストがあれば、すべての要素がNILでなければTに、NILでないならNILにリストを減らしたいと思います。この場合と同様にCommon Lispのブール値のリストをどのように減らしますか?

(apply #'and (get-some-list)) 

:これは私にエラーを与える

[11]> (defun my-and (x y) (and x y)) 
MY-AND 

[12]> (reduce #'my-and '(T T T T T)) 
T 

[13]> (reduce #'my-and '(T T T T NIL)) 
NIL 

はなぜ "#」と" 無効です。

(reduce #'and (get-some-list)) 

これは私が作ってみたが最適です? Common Lispでこれを行うもっと慣用的な方法はありますか?

答えて

8

#'andは、andがマクロであり、関数ではないため無効です。

あなたは、ラムダを使用することにより、名前の関数を定義する必要が周りを取得することができます

(reduce (lambda (x y) (and x y)) (get-some-list) :initial-value t) 

#'のような近道は、しかしありません。

また、everyを識別関数とともに述語として使用することもできます。

+1

あなたの例は、間違った**です。なぜなら、 'reduce'の最初の引数が0または2つの引数で呼び出されるかもしれないからです(CLハイパースペック参照)。また、あなたは '初期値'を提供しません。空のリストや長さが1のリストを減らしたいときは、あなたの例はうまくいきません。正しいバージョンは例えば '(lambda(&optional(x T)(y T)(xy))' 。 –

3

「シャープクォート」記号は、通常の機能でのみ使用できます。

Note that only ordinary functions can be quoted with #’. It is an error to 
quote a macro function or special function this way, or to quote a symbol with 
#’ if that symbol does not name a function. 

> #’if 
Error: IF is not an ordinary function. 

COMMON LISP: A Gentle Introduction to Symbolic Computation, page 202

19

あなたはすべての機能を使用することができます。

(every #'identity '(T T T T T)) -> T 

(every #'identity '(T T T T NIL)) -> NIL 

おそらく最も効率的な方法は、LOOPを使用している:

(loop for element in '(T T T T nil) always element) -> NIL 

利点は、リスト要素に対して関数呼び出しが必要ないことです。

#'は、式の読み取り中にFUNCTIONに展開される読み取りマクロです。したがって#'andは(関数AND)です。

機能がここで記載されている:http://www.lispworks.com/documentation/HyperSpec/Body/s_fn.htm

関数は、関数名またはラムダ式を受け取り、対応する関数オブジェクトを返します。

、ここで定義されています。http://www.lispworks.com/documentation/HyperSpec/Body/m_and.htm

これは、マクロではなく関数であることを述べています。 FUNCTIONには関数が必要であり、対応する関数オブジェクトを返すマクロではないため、(FUNCTION AND)は機能しません。 sepp2kが答えているように、LAMBDAを使用して関数を作成し、その関数内でマクロANDを使用することができます。マクロは値として渡すことはできず、後でFUNCALLまたはAPPLYを介して呼び出されます。これは関数でのみ動作します。

この溶液を

(reduce (lambda (x y) (and x y)) (get-some-list)) 

LAMBDAが(function (lambda (...) ...))(lambda (...) ...)を拡張マクロであるとして記述されています。したがって、上記の

は本当にです:

Common Lispには、値や関数の名前空間との間に違いがあるため

(reduce #'(lambda (x y) (and x y)) (get-some-list)) 

機能が必要とされているように書くことができ

(reduce (function (lambda (x y) (and x y))) (get-some-list)) 

。 REDUCEは、関数をvalueで引数として渡す必要があります。関数の名前空間から関数を取得する必要があります。これはFUNCTIONの目的です。関数オブジェクトを渡したいときはいつも、関数名前空間からそれを取得する必要があります。ローカル関数の場合、例えば

:(FUNCTION(LAMBDA ...))に展開便利なマクロとして

(flet ((my-and (x y) (and x y))) 
    #'my-and) 

LAMBDAは、Common Lispの設計の中に追加されています。

関連する問題