Comenzando con common-lisp

Recursos comunes de aprendizaje de Lisp

Libros en línea

Estos son libros que son de libre acceso en línea.

  • Practical Common Lisp de Peter Seibel es una buena introducción a CL para programadores experimentados, que intenta resaltar desde el principio lo que diferencia a CL de otros lenguajes.
  • Common Lisp: Una introducción suave a la computación simbólica por David S. Touretzky es una buena introducción para las personas nuevas en la programación.
  • [Common Lisp: un enfoque interactivo de Stuart C. Shapiro] (https://www.cse.buffalo.edu/~shapiro/Commonlisp/) se utilizó como libro de texto del curso, y las notas del curso acompañan al libro en el sitio web.
  • Common Lisp, el lenguaje de Guy L. Steele es una descripción del lenguaje Common Lisp. Según CLiki está desactualizado, pero contiene mejores descripciones de la [macro de bucle](http://www.cs.cmu.edu/afs/cs .cmu.edu/project/ai-repository/ai/html/cltl/clm/node235.html#SECTION0030000000000000000000) y [formato](http://www.cs.cmu.edu/afs/cs.cmu.edu/ project/ai-repository/ai/html/cltl/clm/node200.html) que Common Lisp Hyperspec.
  • On Lisp de Paul Graham es un gran libro para Lispers con experiencia intermedia.
  • Let Over Lambda de Doug Hoyte es un libro avanzado sobre Lisp Macros. Varias personas recomendaron que se sienta cómodo con On Lisp antes de leer este libro, y que el comienzo sea lento.

Referencias en línea

  • The Common Lisp Hyperspec es el documento de referencia del lenguaje para Common Lisp.
  • The Common Lisp Cookbook es una lista de recetas útiles de Lisp. También contiene una lista de otras fuentes en línea de información de CL.
  • [Referencia rápida de Common Lisp] (http://clqr.boundp.org/) tiene hojas de referencia imprimibles de Lisp.
  • Lispdoc.com busca documentación en varias fuentes de información Lisp (Practical Common Lisp, Success Lisp, On Lisp, HyperSpec).
  • L1sp.org es un servicio de redirección para la documentación.

Libros sin conexión

Estos son libros que probablemente tendrá que comprar o prestar de una biblioteca.

  • [ANSI Common Lisp por Paul Graham] (http://www.paulgraham.com/acl.html).
  • [Recetas comunes de Lisp por Edmund Weitz] (http://weitz.de/cl-recipes/).
  • Paradigms of Artificial Intelligence Programming tiene muchas aplicaciones interesantes de Lisp, pero ya no es una buena referencia para la IA.

Comunidades en línea

Bibliotecas

  • Quicklisp es el administrador de bibliotecas de Common Lisp y tiene una larga [lista de bibliotecas compatibles](https://www.quicklisp .org/beta/releases.html).
  • Quickdocs alberga la documentación de la biblioteca para muchas bibliotecas CL.
  • Awesome CL es una lista seleccionada por la comunidad de bibliotecas, marcos y otras cosas brillantes ordenadas por categoría.

Entornos Lisp preempaquetados

Estos son entornos de edición de Lisp que son fáciles de instalar y comenzar porque todo lo que necesita está preempaquetado y preconfigurado.

  • Portacle es un entorno Common Lisp portátil y multiplataforma. Incluye un Emacs ligeramente personalizado con Slime, SBCL (una popular implementación de Common Lisp), Quicklisp y Git. No se necesita instalación, por lo que es una manera muy rápida y fácil de comenzar.
  • Lispbox es un IDE (Emacs + SLIME), un entorno Common Lisp (Clozure Common Lisp) y un administrador de bibliotecas (Quicklisp), preempaquetado como archivos para Windows, Mac OS X y Linux. Descendiente de “Lisp in a Box” Recomendado en el libro Practical Common Lisp.
  • No preempaquetado, pero SLIME convierte a Emacs en un IDE de Common Lisp y tiene un [manual de usuario](http://common-lisp. net/project/slime/doc/html/) para ayudarlo a comenzar. Requiere una implementación separada de Common Lisp.

Implementaciones comunes de Lisp

Esta sección enumera algunas implementaciones comunes de CL y sus manuales. A menos que se indique lo contrario, estas son implementaciones de software libre. Consulte también la [Lista de Cliki de implementaciones Common Lisp de software libre] (http://www.cliki.net/Common%20Lisp%20implementation), y la [Lista de Wikipedia de implementaciones comerciales de Common Lisp] (https://en.wikipedia. org/wiki/Common_Lisp#Commercial_implementations).

Expresiones básicas

Probemos alguna expresión básica en el REPL:

CL-USER> (+ 1 2 3)
6
CL-USER> (- 3 1 1)
1
CL-USER> (- 3)
-3
CL-USER> (+ 5.3 (- 3 2) (* 2 2))
10.3
CL-USER> (concatenate 'string "Hello, " "World!")
"Hello, World!"
CL-USER> 

El componente básico de un programa Common Lisp es el formulario. En estos ejemplos tenemos formas de funciones, es decir, expresiones, escritas como lista, en las que el primer elemento es un operador (o función) y el resto de los elementos son los operandos (esto se llama “Notación de prefijo”, o “ Notación polaca”). La escritura de formularios en el REPL provoca su evaluación. En los ejemplos se pueden ver expresiones simples cuyos argumentos son números constantes, cadenas y símbolos (en el caso de 'cadena, que es el nombre de un tipo). También puede ver que los operadores aritméticos pueden tomar cualquier cantidad de argumentos.

Es importante tener en cuenta que los paréntesis son una parte integral de la sintaxis y no se pueden usar libremente como en otros lenguajes de programación. Por ejemplo, lo siguiente es un error:

(+ 5 ((+ 2 4)))
> Error: Car of ((+ 2 4)) is not a function name or lambda-expression. ...

En Common Lisp los formularios también pueden ser datos, símbolos, macro formularios, formularios especiales y formularios lambda. Se pueden escribir para ser evaluados, devolviendo cero, uno o más valores, o se pueden dar como entrada a una macro, que los transforma en otras formas.

Hola, Nombre

Este es un ejemplo un poco más avanzado que muestra algunas características más de common lisp. Comenzamos con una función simple ¡Hola, mundo! y demostramos algunos desarrollos interactivos en el REPL. Tenga en cuenta que cualquier texto desde un punto y coma, ;, hasta el resto de la línea es un comentario.

CL-USER> (defun hello ()
       (format t "Hello, World!~%")) ;We start as before
HELLO
CL-USER> (hello)
Hello, World!
NIL
CL-USER> (defun hello-name (name) ;A function to say hello to anyone
       (format t "Hello, ~a~%" name)) ;~a prints the next argument to format
HELLO-NAME
CL-USER> (hello-name "Jack")
Hello, Jack
NIL
CL-USER> (hello-name "jack") ;doesn't capitalise names
Hello, jack
NIL
CL-USER> (defun hello-name (name) ;format has a feature to convert to title case
       (format t "Hello, ~:(~a~)~%" name)) ;anything between ~:( and ~) gets it
WARNING: redefining COMMON-LISP-USER::HELLO-NAME in DEFUN
HELLO-NAME
CL-USER> (hello-name "jack")
Hello, Jack
NIL
CL-USER> (defun hello-name (name)
       (format t "Hello, ~:(~a~)!~%" name))
WARNING: redefining COMMON-LISP-USER::HELLO-NAME in DEFUN
HELLO-NAME
CL-USER> (hello-name "jack") ;now this works
Hello, Jack!
NIL
CL-USER> (defun hello (&optional (name "world")) ;we can take an optional argument
       (hello-name name)) ;name defaults to "world"
WARNING: redefining COMMON-LISP-USER::HELLO in DEFUN
HELLO
CL-USER> (hello)
Hello, World!
NIL
CL-USER> (hello "jack")
Hello, Jack!
NIL
CL-USER> (hello "john doe") ;note that this capitalises both names
Hello, John Doe!
NIL
CL-USER> (defun hello-person (name &key (number))
       (format t "Hello, ~a ~r" name number)) ;~r prints a number in English
HELLO-PERSON
CL-USER> (hello-person "Louis" :number 16) ;this doesn't quite work
Hello, Louis sixteen
NIL
CL-USER> (defun hello-person (name &key (number))
       (format t "Hello, ~:(~a ~:r~)!" name number)) ;~:r prints an ordinal
WARNING: redefining COMMON-LISP-USER::HELLO-PERSON in DEFUN
HELLO-PERSON
CL-USER> (hello-person "Louis" :number 16)
Hello, Louis Sixteenth!
NIL
CL-USER> (defun hello-person (name &key (number))
       (format t "Hello, ~:(~a [email protected]~)!" name number)) ;[email protected] prints Roman numerals
WARNING: redefining COMMON-LISP-USER::HELLO-PERSON in DEFUN
HELLO-PERSON
CL-USER> (hello-person "Louis" :number 16)
Hello, Louis Xvi!
NIL
CL-USER> (defun hello-person (name &key (number)) ;capitalisation was wrong
       (format t "Hello, ~:(~a~) ~:@r!" name number))
WARNING: redefining COMMON-LISP-USER::HELLO-PERSON in DEFUN
HELLO-PERSON
CL-USER> (hello-person "Louis" :number 16) ;thats better
Hello, Louis XVI!
NIL
CL-USER> (hello-person "Louis") ;we get an error because NIL is not a number
Hello, Louis ; Evaluation aborted on #<SB-FORMAT:FORMAT-ERROR {1006641AB3}>.
CL-USER> (defun say-person (name &key (number 1 number-p)
                                      (title nil) (roman-number t))
       (let ((number (if number-p
                 (typecase number
                   (integer
                (format nil (if roman-number " ~:@r" " ~:(~:r~)") number))
                   (otherwise
                (format nil " ~:(~a~)" number)))
                 "")) ; here we define a variable called number
         (title (if title 
                (format nil "~:(~a~) " title)
                ""))) ; and here one called title
         (format nil "~a~:(~a~)~a" title name number))) ;we use them here

SAY-PERSON
CL-USER> (say-person "John") ;some examples
"John"
CL-USER> (say-person "john doe")
"John Doe"
CL-USER> (say-person "john doe" :number "JR")
"John Doe Jr"
CL-USER> (say-person "john doe" :number "Junior")
"John Doe Junior"
CL-USER> (say-person "john doe" :number 1)
"John Doe I"
CL-USER> (say-person "john doe" :number 1 :roman-number nil) ;this is wrong
"John Doe First"
CL-USER> (defun say-person (name &key (number 1 number-p)
                                      (title nil) (roman-number t))
       (let ((number (if number-p
                 (typecase number
                   (integer
                (format nil (if roman-number " ~:@r" " the ~:(~:r~)") number))
                   (otherwise
                (format nil " ~:(~a~)" number)))
                 ""))
         (title (if title 
                (format nil "~:(~a~) " title)
                "")))
         (format nil "~a~:(~a~)~a" title name number)))
WARNING: redefining COMMON-LISP-USER::SAY-PERSON in DEFUN
SAY-PERSON
CL-USER> (say-person "john doe" :number 1 :roman-number nil) ;thats better
"John Doe the First"
CL-USER> (say-person "louis" :title "king" :number 16 :roman-number nil)
"King Louis the Sixteenth"
CL-USER> (say-person "louis" :title "king" :number 16 :roman-number t)
"King Louis XVI"
CL-USER> (defun hello (&optional (name "World") &rest arguments) ;now we will just
       (apply #'hello-name name arguments)) ;pass all arguments to hello-name
WARNING: redefining COMMON-LISP-USER::HELLO in DEFUN
HELLO
CL-USER> (defun hello-name (name &rest arguments) ;which will now just use
       (format t "Hello, ~a!" (apply #'say-person name arguments))) ;say-person
WARNING: redefining COMMON-LISP-USER::HELLO-NAME in DEFUN
HELLO-NAME
CL-USER> (hello "louis" :title "king" :number 16) ;this works now
Hello, King Louis XVI!
NIL
CL-USER>

Esto destaca algunas de las características avanzadas de la función formato de Common Lisp, así como algunas características como parámetros opcionales y argumentos de palabras clave (por ejemplo, :número). Esto también da un ejemplo de desarrollo interactivo en un REPL en common lisp.

El sencillo programa Hello World en REPL

Common Lisp REPL es un entorno interactivo. Cada formulario escrito después del indicador se evalúa y su valor se imprime posteriormente como resultado de la evaluación. Entonces, el “¡Hola, mundo!” más simple posible programa en Common Lisp es:

CL-USER> "Hello, World!"
"Hello, World!"
CL-USER>

Lo que sucede aquí es que se proporciona una constante de cadena en la entrada del REPL, se evalúa y se imprime el resultado. Lo que se puede ver en este ejemplo es que las cadenas, como los números, los símbolos especiales como ‘NIL’ y ‘T’ y algunos otros literales, son formas autoevaluadas: es decir, se evalúan a sí mismas.

Expresiones lambda y funciones anónimas

Una función anónima se puede definir sin nombre a través de una Expresión Lambda. Para definir este tipo de funciones, se utiliza la palabra clave lambda en lugar de la palabra clave defun. Las siguientes líneas son todas equivalentes y definen funciones anónimas que generan la suma de dos números:

(lambda (x y) (+ x y))
(function (lambda (x y) (+ x y)))
#'(lambda (x y) (+ x y))

Su utilidad es notable cuando se crean formularios lambda, es decir, un formulario que es una lista donde el primer elemento es la expresión lambda y los elementos restantes son los argumentos de la función anónima. Ejemplos (ejecución en línea):

(print ((lambda (x y) (+ x y)) 1 2)) ; >> 3

(print (mapcar (lambda (x y) (+ x y)) '(1 2 3) '(2 -5 0))) ; >> (3 -3 3)

Suma de la lista de enteros

(defun sum-list-integers (list)
    (reduce '+ list))

; 10
(sum-list-integers '(1 2 3 4))

; 55
(sum-list-integers '(1 2 3 4 5 6 7 8 9 10))

Hola Mundo

Lo que sigue es un extracto de una sesión de REPL con Common Lisp en la que un “¡Hola, mundo!” se define y ejecuta la función. Consulte los comentarios al final de esta página para obtener una descripción más completa de un REPL.

CL-USER> (defun hello ()
           (format t "Hello, World!~%"))
HELLO
CL-USER> (hello)
Hello, World!
NIL
CL-USER> 

Esto define la “función” de cero argumentos llamados hola, que escribirán la cadena "¡Hola, mundo!" seguido de una nueva línea en la salida estándar y devolverá NIL.

Para definir una función escribimos

(defun name (parameters...)
  code...)

En este caso, la función se llama hola, no toma parámetros y el código que ejecuta es para hacer una llamada de función. El valor devuelto por una función lisp es el último bit de código en la función que se ejecutará, por lo que hello devuelve lo que (format t "Hello, World!~%") devuelve.

En lisp para llamar a una función, uno escribe (argumentos de nombre de función...) donde nombre de función es el nombre de la función y argumentos... es la lista (separada por espacios) de argumentos para la función. llamar. Hay algunos casos especiales que parecen llamadas a funciones pero no lo son, por ejemplo, en el código anterior no hay una función defun que se llame, se trata de manera especial y define una función en su lugar.

En el segundo aviso de REPL, después de haber definido la función hola, la llamamos sin parámetros escribiendo (hola). Esto, a su vez, llamará a la función format con los parámetros t y "Hello, World!~%". La función format produce una salida formateada basada en los argumentos que se le dan (un poco como una versión avanzada de printf en C). El primer argumento le dice a dónde enviar la salida, con t que significa salida estándar. El segundo argumento le dice qué imprimir (y cómo interpretar cualquier parámetro adicional). La directiva (código especial en el segundo argumento) ~% le dice a format que imprima una nueva línea (es decir, en UNIX podría escribir \n y en Windows \r\n). El formato generalmente devuelve NIL (un poco como NULL en otros idiomas).

Después del segundo mensaje, vemos que Hello, World se imprimió y en la siguiente línea el valor devuelto fue NIL.