common-lispCommencer avec Common-Lisp


Remarques

Ceci est une fonction simple hello world dans Common Lisp. Des exemples vont imprimer le texte Hello, World! (sans les guillemets, suivi d'une nouvelle ligne) à la sortie standard.

Common Lisp est un langage de programmation largement utilisé de manière interactive en utilisant une interface appelée REPL. Le REPL (Read Eval Print Loop) permet de taper du code, de l’évaluer (voir) et de voir les résultats immédiatement. L'invite pour la REPL (à laquelle on tape le code à exécuter) est indiquée par CL-USER> . Parfois, quelque chose d'autre que CL-USER apparaîtra avant le > mais ceci est toujours une REPL.

Après l'invite, il y a un code, généralement un seul mot (un nom de variable) ou un formulaire (une liste de mots / formes entre ( et ) ) (un appel de fonction ou une déclaration, etc.). Sur la ligne suivante, il y aura toute sortie que le programme imprime (ou rien si le programme n’imprime rien), puis les valeurs renvoyées en évaluant l’expression. Normalement, une expression renvoie une valeur mais si elle renvoie plusieurs valeurs, elles apparaissent une fois par ligne.

Versions

Version Date de sortie
Lisp commun 1984-01-01
ANSI Common Lisp 1994-01-01

Expressions de base

Essayons une expression de base dans le 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> 
 

Le bloc de construction de base d'un programme Common Lisp est le formulaire . Dans ces exemples, nous avons des formes de fonctions , c’est-à-dire des expressions, écrites sous forme de liste, dans lesquelles le premier élément est un opérateur (ou une fonction) et le reste des éléments les opérandes ”). L'écriture de formulaires dans le REPL entraîne leur évaluation. Dans les exemples, vous pouvez voir des expressions simples dont les arguments sont des nombres constants, des chaînes et des symboles (dans le cas de 'string , qui est le nom d'un type). Vous pouvez également voir que les opérateurs arithmétiques peuvent prendre n'importe quel nombre d'arguments.

Il est important de noter que les parenthèses font partie intégrante de la syntaxe et ne peuvent pas être utilisées librement comme dans d'autres langages de programmation. Par exemple, ce qui suit est une erreur:

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

Dans Common Lisp, les formulaires peuvent également être des données, des symboles, des formes de macros, des formulaires spéciaux et des formes lambda. Ils peuvent être écrits pour être évalués, retourner zéro, une ou plusieurs valeurs, ou peuvent être donnés en entrée à une macro, qui les transforment sous d'autres formes.

Ressources d'apprentissage Common Lisp

Livres en ligne

Ce sont des livres librement accessibles en ligne.

Références en ligne

  • Le Common Lisp Hyperspec est le document de référence de langage pour Common Lisp.
  • Le Common Lisp Cookbook est une liste de recettes Lisp utiles. Contient également une liste d'autres sources en ligne d'informations sur la CL.
  • Common Lisp Quick Reference a des feuilles de référence imprimables Lisp.
  • Lispdoc.com recherche plusieurs sources d'informations Lisp (Common Lisp pratique, Lisp réussi, On Lisp, HyperSpec) pour la documentation.
  • L1sp.org est un service de redirection pour la documentation.

Livres hors ligne

Ce sont des livres que vous devrez probablement acheter ou prêter dans une bibliothèque.

Communautés en ligne

Bibliothèques

  • Quicklisp est un gestionnaire de bibliothèque pour Common Lisp et possède une longue liste de bibliothèques prises en charge .
  • Quickdocs héberge la documentation de la bibliothèque pour de nombreuses bibliothèques CL.
  • Awesome CL est une liste organisée par les communautés de bibliothèques, de frameworks et d’autres éléments brillants, classés par catégorie.

Environnements Lisp préemballés

Ce sont des environnements d'édition Lisp faciles à installer et à utiliser car tout ce dont vous avez besoin est pré-packagé et pré-configuré.

  • Portacle est un environnement Common Lisp portable et multiplateforme. Il embarque un Emacs légèrement personnalisé avec Slime, SBCL (une implémentation Common Lisp populaire), Quicklisp et Git. Aucune installation nécessaire, c'est donc un moyen très rapide et facile de démarrer.
  • Lispbox est un IDE (Emacs + SLIME), un environnement Common Lisp (Clozure Common Lisp) et un gestionnaire de bibliothèque (Quicklisp), pré-emballés en tant qu'archives pour Windows, Mac OSX et Linux. Descendant de "Lisp in a Box" Recommandé dans le livre Practical Common Lisp.
  • Non préemballé, mais SLIME transforme Emacs en IDE Common Lisp et dispose d'un manuel d'utilisation pour vous aider à démarrer. Nécessite une implémentation Common Lisp distincte.

Implémentations Lisp communes

Cette section répertorie certaines implémentations CL et leurs manuels. Sauf indication contraire, il s'agit d'implémentations de logiciels libres. Voir aussi la liste des implémentations Common Lisp du logiciel libre , et la liste des implémentations Common Lisp commerciales de Wikipedia .

Bonjour le monde

Ce qui suit est un extrait d'une session REPL avec Common Lisp dans laquelle un "Hello, World!" la fonction est définie et exécutée. Voir les remarques au bas de cette page pour une description plus détaillée d'une REPL.

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

Ceci définit la "fonction" de zéro argument nommé hello , qui écrira la chaîne "Hello, World!" suivi d'une nouvelle ligne à la sortie standard et retourne NIL .

Pour définir une fonction on écrit

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

Dans ce cas, la fonction est appelée hello , ne prend aucun paramètre et le code qu’elle exécute fait un appel de fonction. La valeur renvoyée par une fonction lisp est le dernier bit de code de la fonction à exécuter, donc hello renvoie le résultat (format t "Hello, World!~%") .

Dans lisp pour appeler une fonction, on écrit (function-name arguments...)function-name est le nom de la fonction et arguments... est la liste d'arguments (séparés par des espaces) de l'appel. Il y a des cas particuliers qui ressemblent à des appels de fonction mais qui ne sont pas, par exemple, dans le code ci-dessus, il n'y a pas de fonction defun appelée, elle est traitée spécialement et définit une fonction à la place.

À la deuxième invite de la REPL, après avoir défini la fonction hello , nous l’appelons sans paramètres en écrivant (hello) . Cela appellera à son tour la fonction de format avec les paramètres t et "Hello, World!~%" . La fonction format produit une sortie formatée en fonction des arguments qui lui sont donnés (un peu comme une version avancée de printf en C). Le premier argument lui indique où sortir, avec t signifiant sortie standard. Le second argument lui indique quoi imprimer (et comment interpréter les paramètres supplémentaires). La directive (code spécial dans le deuxième argument) ~% indique au format d’imprimer une nouvelle ligne (c’est-à-dire que sous UNIX, elle peut écrire \n et sur Windows \r\n ). Le format retourne généralement NIL (un peu comme NULL dans les autres langues).

Après la deuxième invite, nous voyons que Hello, World a été imprimé et à la ligne suivante que la valeur renvoyée était NIL .

Bonjour, Nom

Ceci est un exemple légèrement plus avancé qui montre quelques fonctionnalités supplémentaires du lisp commun. Nous commençons par un simple Hello, World! fonction et démontrer un développement interactif au REPL. Notez que tout texte à partir d' un point - virgule ; , au reste de la ligne est un commentaire.

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 ~@r~)!" name number)) ;~@r 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>
 

Cela met en évidence certaines des fonctionnalités avancées de la fonction de format de Common Lisp, ainsi que certaines fonctionnalités telles que les paramètres facultatifs et les arguments de mot-clé (par exemple :number ). Cela donne également un exemple de développement interactif à une REPL en langage courant.

Expressions lambda et fonctions anonymes

Une fonction anonyme peut être définie sans nom via une expression Lambda . Pour définir ce type de fonctions, le mot-clé lambda est utilisé à la place du mot-clé defun . Les lignes suivantes sont toutes équivalentes et définissent des fonctions anonymes qui génèrent la somme de deux nombres:

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

Leur utilité est notable lors de la création de formulaires Lambda , c.-à-d. Un formulaire qui est une liste où le premier élément est l'expression lambda et les éléments restants sont les arguments de la fonction anonyme. Exemples ( exécution en ligne ):

(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)
 

Somme de la liste d'entiers

(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))
 

Le programme simple Hello World dans REPL

Common Lisp REPL est un environnement interactif. Chaque formulaire écrit après l'invite est évalué et sa valeur est ensuite imprimée à la suite de l'évaluation. Ainsi, le programme le plus simple possible «Bonjour, Monde!» Dans Common Lisp est:

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

Ce qui se passe ici est qu'un costant de chaîne est donné en entrée à la REPL, il est évalué et le résultat est imprimé. Ce que l'on peut voir dans cet exemple est que les chaînes, comme les nombres, les symboles spéciaux comme NIL et T et quelques autres littéraux, sont des formulaires auto- évaluables: c'est-à-dire qu'ils se évaluent eux-mêmes.