2010-12-26 16 views
11

Biorąc pod uwagę listę wartości, chcę zmniejszyć listę do T, jeśli wszystkie elementy nie są NIL, NIL, jeśli nie. To daje mi błąd:Jak zmniejszyć listę wartości logicznych w Common Lisp?

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

Jak to robi:

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

Jest to najlepszy jaki wymyślić:

[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 

Dlaczego "#" i" nieprawidłowa ? Czy istnieje bardziej idiomatyczny sposób na to w Common Lisp?

Odpowiedz

8

#'and jest nieprawidłowy, ponieważ and jest makrem, a nie funkcją.

można ominąć konieczności definiowania nazwie funkcji, za pomocą lambda:

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

Nie ma skrót jak #' chociaż.

Alternatywnie można również użyć every z funkcją identyfikacji jako predykatem.

+1

Twój przykład jest ** niepoprawny **, ponieważ pierwszy argument "zmniejszenia" może być wywołany z zerowym lub dwoma argumentami "(zobacz CL hyperspec). Ponadto nie podaje się żadnej "wartości początkowej". Jako całość, twój przykład nie działa, gdy chcesz zmniejszyć pustą listę lub listy o długości 1. Poprawną wersją jest np. '(Lambda (i opcjonalnie (x T) (y T)) (i xy))' . –

3

Możesz użyć symbolu "ostrych cytatów" tylko przy zwykłych funkcjach.

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

Można użyć każdej funkcji:

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

i

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

Prawdopodobnie najbardziej skutecznym sposobem jest użycie LOOP:

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

Zaletą jest to, że nie są wymagane wywołania funkcji przez elementy listy.

#' to makro odczytu, które rozwija się w funkcji FUNCTION podczas odczytu wyrażenia. Tak więc #'and jest (FUNCTION AND).

funkcja opisana tutaj: http://www.lispworks.com/documentation/HyperSpec/Body/s_fn.htm

funkcja przyjmuje nazwę funkcji lub wyrażenia lambda i zwraca odpowiedni obiekt funkcji.

i jest zdefiniowany tutaj: http://www.lispworks.com/documentation/HyperSpec/Body/m_and.htm

Mówi, że I jest makro, a nie funkcja. W konsekwencji funkcja (FUNCTION AND) nie działa, ponieważ funkcja FUNCTION potrzebuje funkcji, a nie makra do zwrócenia odpowiedniego obiektu funkcji. Jak opisuje sepp2k w swojej odpowiedzi, możesz utworzyć funkcję za pomocą LAMBDA i użyć makra ORAZ wewnątrz tej funkcji. Makr nie można przekazywać jako wartości, a następnie wywoływać za pośrednictwem FUNCALL lub APPLY. Działa to tylko z funkcjami.

To rozwiązanie jest napisane jak

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

LAMBDA jest makro, które rozszerza (lambda (...) ...) do (function (lambda (...) ...)).

Więc powyżej jest naprawdę:

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

który może być zapisany jako konieczna jest

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

FUNKCJI bo Common Lisp robi różnicę pomiędzy nazw dla wartości i funkcji. REDUCE wymaga, aby funkcja była przekazywana jako argument przez wartość. Musimy więc pobrać funkcję z przestrzeni nazw funkcji - co jest celem FUNKCJI. Ilekroć chcemy przekazać obiekt funkcji, musimy pobrać go z przestrzeni nazw funkcji.

Na przykład w przypadku lokalnego funkcji:

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

LAMBDA jako makro spożywczy, który rozszerza się (function (lambda ...)) został dodany podczas projektowania Common Lisp.