Buscar..


Sintaxis

  • (nombre de la función) ; recupera la función objeto de ese nombre
  • #'nombre ; azúcar sintáctica para (nombre de la función)
  • (símbolo de función de símbolo); devuelve la función vinculada al símbolo
  • (función funcs args ...); llamar a la función con args
  • (aplicar la función arglista); Función de llamada con argumentos dados en una lista.
  • (aplicar la función arg1 arg2 ... argn arglist); Función de llamada con argumentos dados por arg1, arg2, ..., argn y el resto en la lista arglist

Parámetros

Parámetro Detalles
nombre algún símbolo (no evaluado) que nombra una función
símbolo un símbolo
función una función que se va a llamar
args ... cero o más argumentos ( no una lista de argumentos)
arglista una lista que contiene argumentos para pasar a una función
arg1, arg2, ..., argn Cada uno es un único argumento que se pasa a una función.

Observaciones

Cuando se habla de lenguajes similares a Lisp, existe una distinción común entre lo que se conoce como Lisp-1 y Lisp-2. En un Lisp-1, los símbolos solo tienen un valor y si un símbolo se refiere a una función, entonces el valor de ese símbolo será esa función. En un Lisp-2, los símbolos pueden tener valores y funciones asociadas por separado, por lo que se requiere una forma especial para referirse a la función almacenada en un símbolo en lugar del valor.

Common Lisp es básicamente un Lisp-2, sin embargo, en realidad hay más de 2 espacios de nombres (cosas a las que los símbolos pueden referirse): los símbolos pueden referirse a valores, funciones, tipos y etiquetas, por ejemplo.

Definiendo funciones anónimas.

Las funciones en Common Lisp son valores de primera clase . Se puede crear una función anónima usando lambda . Por ejemplo, aquí hay una función de 3 argumentos que luego llamamos usando 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

Las funciones anónimas también se pueden utilizar directamente. Common Lisp proporciona una sintaxis para ello.

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

Las funciones anónimas también se pueden almacenar como funciones globales:

(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

Las expresiones lambda citadas no son funciones

Tenga en cuenta que las expresiones lambda citadas no son funciones en Common Lisp. Esto no funciona:

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

Para convertir una expresión lambda entrecomillada a una función, use coerce , eval o 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>

Haciendo referencia a las funciones existentes

Cualquier símbolo en Common Lisp tiene una ranura para una variable a vincular y una ranura separada para una función a vincular.

Tenga en cuenta que la denominación en este ejemplo es solo para ilustración. Las variables globales no deberían llamarse foo , sino *foo* . La última notación es una convención para dejar en claro que la variable es una variable especial que utiliza el enlace dinámico .

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

Funciones de orden superior

Common Lisp contiene muchas funciones de orden superior que son funciones pasadas para los argumentos y las llaman. Tal vez los más fundamentales sean funcall y de 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)

Hay muchas otras funciones de orden superior que, por ejemplo, aplican una función muchas veces a los elementos de una lista.

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)

Sumando una lista

La función de reducción se puede utilizar para sumar los elementos de una lista.

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

Por defecto, reducir realiza una reducción asociativa a la izquierda , lo que significa que la suma 10 se calcula como

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

Los primeros dos elementos se suman primero, y luego ese resultado (3) se agrega al siguiente elemento (3) para producir 6, que a su vez se agrega a 4, para producir el resultado final.

Esto es más seguro que usar aplicar (por ejemplo, en (aplicar '+' (1 2 3 4)) porque la longitud de la lista de argumentos que se puede pasar a aplicar es limitada (consulte el límite de argumentos de llamadas ), y la reducción funcionará Con funciones que solo toman dos argumentos.

Al especificar el argumento de la palabra clave desde el final , reducir procesará la lista en la otra dirección, lo que significa que la suma se computa en el orden inverso. Es decir

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

está computando

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

Implementación de reversa y reventa.

Common Lisp ya tiene una función inversa , pero si no lo tenía, entonces podría implementarse fácilmente usando reducir . Dada una lista como

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

la lista invertida es

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

Puede que no sea un uso obvio de reducir , pero si tenemos una función de "contras invertida", digamos xcons , de modo que

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

Entonces

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

Que es una reducción.

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

Common Lisp tiene otra función útil, revappend , que es una combinación de reversa y anexa . Conceptualmente, invierte una lista y la agrega a alguna cola:

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

Esto también se puede implementar con reducir . De hecho, es lo mismo que la implementación del reverso anterior, excepto que el valor inicial debería ser (4 5 6) en lugar de la lista vacía.

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

Cierres

Las funciones recuerdan el ámbito léxico en el que se definieron. Debido a esto, podemos incluir un lambda en un let para definir los cierres.

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

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

En el ejemplo anterior, la variable de contador solo es accesible a la función anónima. Esto se ve más claramente en el siguiente ejemplo.

(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

Definiendo funciones que toman funciones y devuelven funciones.

Un ejemplo simple:

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

El ejemplo clásico de la composición de la función : ( 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
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow