Szukaj…


Składnia

  • (nazwa funkcji); pobiera obiekt funkcji o tej nazwie
  • #'Nazwa ; cukier składniowy dla (nazwa funkcji)
  • (symbol funkcji symbolicznej); zwraca funkcję powiązaną z symbolem
  • (Argumenty funkcji funcall ...); funkcja wywołania z argumentami
  • (zastosuj funkcję arglist); funkcja wywołania z argumentami podanymi na liście
  • (zastosuj funkcję arg1 arg2 ... argn arglist); funkcja wywołania z argumentami podanymi przez arg1, arg2, ..., argn i resztę na liście arglist

Parametry

Parametr Detale
Nazwa jakiś (nieoceniony) symbol, który nazywa funkcję
symbol symbol
funkcjonować funkcja, która ma zostać wywołana
args ... zero lub więcej argumentów ( nie lista argumentów)
arglist lista zawierająca argumenty, które należy przekazać do funkcji
arg1, arg2, ..., argn każdy jest pojedynczym argumentem przekazywanym do funkcji

Uwagi

Mówiąc o językach podobnych do Lisp, istnieje powszechne rozróżnienie między tak zwanymi Lisp-1 i Lisp-2. W Lisp-1 symbole mają tylko wartość, a jeśli symbol odnosi się do funkcji, wówczas wartością tego symbolu będzie ta funkcja. W Lisp-2 symbole mogą mieć osobne powiązane wartości i funkcje, dlatego wymagana jest specjalna forma do odniesienia do funkcji przechowywanej w symbolu zamiast wartości.

Common Lisp jest w zasadzie Lisp-2, ale w rzeczywistości istnieją więcej niż 2 przestrzenie nazw (rzeczy, do których symbole mogą się odnosić) - symbole mogą odnosić się na przykład do wartości, funkcji, typów i znaczników.

Definiowanie anonimowych funkcji

Funkcje w Common Lisp są wartościami pierwszej klasy . Anonimową funkcję można utworzyć za pomocą lambda . Na przykład tutaj jest funkcja 3 argumentów, które następnie wywołujemy za pomocą funcall

CL-USER> (lambda (a b c) (+ a (* b c)))
#<FUNCTION (LAMBDA (A B C)) {10034F484B}>
CL-USER> (defvar *foo* (lambda (a b c) (+ a (* b c))))
*FOO*
CL-USER> (funcall *foo* 1 2 3)
7

Z funkcji anonimowych można również korzystać bezpośrednio. Common Lisp zapewnia dla niego składnię.

((lambda (a b c) (+ a (* b c)))    ; the lambda expression as the first
                                   ; element in a form
  1 2 3)                           ; followed by the arguments

Funkcje anonimowe można również przechowywać jako funkcje globalne:

(let ((a-function (lambda (a b c) (+ a (* b c)))))      ; our anonymous function
  (setf (symbol-function 'some-function) a-function))   ; storing it

(some-function 1 2 3)                                   ; calling it with the name

Cytowane wyrażenia lambda nie są funkcjami

Zauważ, że cytowane wyrażenia lambda nie są funkcjami w Common Lisp. To nie działa:

(funcall '(lambda (x) x)
         42)

Aby przekonwertować cytowane wyrażenie lambda na funkcję, użyj coerce , eval lub funcall :

CL-USER > (coerce '(lambda (x) x) 'function)
#<anonymous interpreted function 4060000A7C>

CL-USER > (eval '(lambda (x) x))
#<anonymous interpreted function 4060000B9C>

CL-USER > (compile nil '(lambda (x) x))
#<Function 17 4060000CCC>

Odnosząc się do istniejących funkcji

Każdy symbol w Common Lisp ma miejsce na zmienną, która ma zostać powiązana, oraz osobny punkt na funkcję, która ma zostać powiązana.

Zauważ, że w tym przykładzie nazewnictwo służy wyłącznie do ilustracji. Zmienne globalne nie powinny mieć nazwy foo , ale *foo* . Ten ostatni zapis jest konwencją, aby wyjaśnić, że zmienna jest specjalną zmienną wykorzystującą dynamiczne wiązanie .

CL-USER> (boundp 'foo) ;is FOO defined as a variable?
NIL
CL-USER> (defvar foo 7)
FOO
CL-USER> (boundp 'foo)
T
CL-USER> foo
7
CL-USER> (symbol-value 'foo)
7
CL-USER> (fboundp 'foo) ;is FOO defined as a function?
NIL
CL-USER> (defun foo (x y) (+ (* x x) (* y y)))
FOO
CL-USER> (fboundp 'foo)
T
CL-USER> foo
7
CL-USER> (symbol-function 'foo)
#<FUNCTION FOO>
CL-USER> (function foo)
#<FUNCTION FOO>
CL-USER> (equalp (quote #'foo) (quote (function foo)))
T
CL-USER> (eq (symbol-function 'foo) #'foo)
T
CL-USER> (foo 4 3)
25
CL-USER> (funcall foo 4 3)
;get an error: 7 is not a function
CL-USER> (funcall #'foo 4 3)
25
CL-USER> (defvar bar #'foo)
BAR
CL-USER> bar
#<FUNCTION FOO>
CL-USER> (funcall bar 4 3)
25
CL-USER> #'+
#<FUNCTION +>
CL-USER> (funcall #'+ 2 3)
5

Funkcje wyższego rzędu

Common Lisp zawiera wiele funkcji wyższego rzędu, które są przekazywane do argumentów i wywołują je. Być może najbardziej podstawowe są funcall i apply :

CL-USER> (list 1 2 3)
(1 2 3)
CL-USER> (funcall #'list 1 2 3)
(1 2 3)
CL-USER> (funcall #'list 1 2 3 4 5)
(1 2 3 4 5)
CL-USER> (apply #'list '(1 2 3))
(1 2 3)
CL-USER> (apply #'list 1 2 '(4 5))
(1 2 3 4 5)
CL-USER> (apply #'+ 1 (list 2 3))
6
CL-USER> (defun my-funcall (function &rest args)
           (apply function args))
MY-FUNCALL
CL-USER> (my-funcall #'list 1 2 3)
(1 2 3)

Istnieje wiele innych funkcji wyższego rzędu, które na przykład wielokrotnie stosują funkcję do elementów listy.

CL-USER> (map 'list #'/ '(1 2 3 4))
(1 1/2 1/3 1/4)
CL-USER> (map 'vector #'+ '(1 2 3 4 5) #(5 4 3 2 10))
#(6 6 6 6 15)
CL-USER> (reduce #'+ '(1 2 3 4 5))
15
CL-USER> (remove-if #'evenp '(1 2 3 4 5))
(1 3 5)

Podsumowanie listy

Funkcja zmniejszania może służyć do sumowania elementów na liście.

(reduce '+ '(1 2 3 4))
;;=> 10

Domyślnie redukcja wykonuje redukcję lewostronną , co oznacza, że suma 10 jest obliczana jako

(+ (+ (+ 1 2) 3) 4)

Pierwsze dwa elementy są najpierw sumowane, a następnie ten wynik (3) jest dodawany do następnego elementu (3), aby uzyskać 6, które z kolei dodaje się do 4, aby uzyskać końcowy wynik.

Jest to bezpieczniejsze niż użycie polecenia zastosuj (np. W (zastosuj „+” (1 2 3 4)), ponieważ długość listy argumentów, którą można przekazać do zastosowania, jest ograniczona (patrz limit argumentów wywołania ), a redukcja zadziała z funkcjami, które biorą tylko dwa argumenty.

Podając argument słowa kluczowego od końca , redukcja przetworzy listę w innym kierunku, co oznacza, że suma jest obliczana w odwrotnej kolejności. To jest

(reduce '+ (1 2 3 4) :from-end t)
;;=> 10

jest informatyka

(+ 1 (+ 2 (+ 3 4)))

Wdrażanie rewersu i odnawianie

Common Lisp ma już funkcję odwrotną , ale jeśli nie, to można ją łatwo wdrożyć za pomocą funkcji zmniejsz . Biorąc pod uwagę listę jak

(1 2 3) === (cons 1 (cons 2 (cons 3 '())))

lista jest odwrócona

(cons 3 (cons 2 (cons 1 '()))) === (3 2 1)

Może to nie być oczywiste użycie funkcji zmniejszania , ale jeśli mamy funkcję „odwróconych wad”, powiedzmy xcons , na przykład

(xcons 1 2) === (2 . 1)

Następnie

(xcons (xcons (xcons () 1) 2) 3)

co jest redukcją.

(reduce (lambda (x y)
          (cons y x))
        '(1 2 3 4)
        :initial-value '())
;=> (4 3 2 1)

Common Lisp ma kolejną przydatną funkcję, revappend , która jest kombinacją rewersu i append . Koncepcyjnie odwraca listę i dołącza ją do jakiegoś ogona:

(revappend '(3 2 1) '(4 5 6))
;;=> (1 2 3 4 5 6)

Można to również zrealizować za pomocą funkcji zmniejszania . W rzeczywistości jest to to samo, co implementacja odwrotności powyżej, z tą różnicą, że wartość początkowa musiałaby wynosić (4 5 6) zamiast pustej listy.

(reduce (lambda (x y)
          (cons y x))
        '(3 2 1)
        :initial-value '(4 5 6))
;=> (1 2 3 4 5 6)

Domknięcia

Funkcje zapamiętują zakres leksykalny, w którym zostały zdefiniowane. Z tego powodu możemy zawrzeć lambda w let, aby zdefiniować zamknięcia.

(defvar *counter* (let ((count 0))
                    (lambda () (incf count))))

(funcall *counter*) ;; => 1
(funcall *counter*) ;; = 2

W powyższym przykładzie zmienna licznika jest dostępna tylko dla funkcji anonimowej. Widać to wyraźniej w poniższym przykładzie

(defvar *counter-1* (make-counter))
(defvar *counter-2* (make-counter))

(funcall *counter-1*) ;; => 1
(funcall *counter-1*) ;; => 2
(funcall *counter-2*) ;; => 1
(funcall *counter-1*) ;; => 3

Definiowanie funkcji, które przyjmują funkcje i zwracają funkcje

Prosty przykład:

CL-USER> (defun make-apply-twice (fun)
           "return a new function that applies twice the function`fun' to its argument"
           (lambda (x)
             (funcall fun (funcall fun x))))
MAKE-APPLY-TWICE
CL-USER> (funcall (make-apply-twice #'1+) 3)
5
CL-USER> (let ((pow4 (make-apply-twice (lambda (x) (* x x)))))
           (funcall pow4 3))
81

Klasyczny przykład składu funkcji : ( fgh ) ( x ) = f ( g ( h ( x )):

CL-USER> (defun compose (&rest funs)
           "return a new function obtained by the functional compositions of the parameters"
           (if (null funs) 
               #'identity
               (let ((rest-funs (apply #'compose (rest funs))))
                 (lambda (x) (funcall (first funs) (funcall rest-funs x))))))
COMPOSE
CL-USER> (defun square (x) (* x x))
SQUARE
CL-USER> (funcall (compose #'square #'1+ #'square) 3)
100  ;; => equivalent to (square (1+ (square 3)))


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow