Disclamer: je ne connais pas bien OCaml, par contre je commence à accumuler les projets en lisp, alors je me permet de partager mes expériences.
Tout d'abord, le Lisp a une syntaxe extrêmement simple que l'on maîtrise en 10 minutes :
(commande argument1 argument2 argument3)
Un programme en Lisp n'étant qu'une liste d'expressions, on peu manipuler un programme en Lisp comme une donnée quelconque. Ce qui est un avantage pour faire de l'IA (voir le PAIP de Peter Norvig [1] qui est très impressionnant).
Certains critique le trop grand nombre de parenthèses. En fait, elles permettent de délimiter très clairement chaque expression. Par exemple, ce n'est pas nécessaire de connaître l'ordre d'évaluation des différents opérateurs. Comparer :
1+2+3+4+5+6 à (+ 1 2 3 4 5 6)
et 2*3+4*5 à (+ (* 2 3) (* 4 5)).
D'autre part, tout bon éditeur de texte permet de repérer les parenthèses correspondantes et d'indenter correctement le code.
Avec un peu d'habitude, on ne vois plus les parenthèses. De plus, ce qui me manque quand je recode avec d'autres langages, c'est la sélection d'expression : on sélectionne la 1ère parenthèses, on saute à la parenthèse correspondante et on manipule tout le bloc.
Ensuite, le Lisp est très expressif, on utilise en général des noms longs et signifiant ce qu'ils font.
Par exemple: (first '(toto titi plop)) renvoie toto.
Ou pour la gestion des fichiers :
(with-open-file (stream "my-file.txt" :direction :output :if-exists :supersede)
(format stream "j'écris ça dans my-file.txt~%"))
Les macros sont un des gros point fort du Lisp : on peut étendre le langage pour le modeler à ce que l'on veut faire.
Par exemple, je retrouve assez souvent la forme suivante pour la gestion de personnages dans un MUD qui envoi un message à tout les personnages sauf au personnage qui envoi le message :
(dolist (cible (contenu (trouve-contenant perso *monde*)))
(when (and (perso-p cible)
(not (eql cible perso)))
(send-to-perso cible "bla bla bla")
bla bla bla))
plutôt que de répéter (à l'infini et par copier/coller) ce code, j'ai juste écrit la macro suivante :
maintenant, pour envoyer un message à tout les autres personnages, j'ai juste à écrire :
(do-for-all-perso (cible perso)
(send-to-perso cible "bla bla bla")
bla bla bla)
Les macros sont extrêmement puissantes et permettent d'adapter le langage. Certains les utilisent pour créer des langages spécifiques à leurs domaines d'applications, d'autre par exemple pour avoir la notation infix [2] dans leur programme.
Pour plus de détails sur les macros, la lecture de OnLisp [3] de Paul Graham est un bon point de départ.
Un autre reproche que l'on peut faire au Lisp est qu'il n'a pas de typage statique. Personnellement je trouve que le typage dynamique procure une souplesse très appréciable. Toujours pour l'exemple du MUD, un personnage pourra commencer une partie en tant que simple paysan (la classe paysan) et au cours du jeu acquérir de l'expérience et devenir un magicien (on le change de classe et sa classe devient magicien).
Un autre usage qui revient assez couramment est que l'on peut faire des fonctions qui agirons différemment suivant le type de ces arguments. Exemple :
(defun ma-fonction-add (x y)
(typecase x
(integer (+ x y))
(string (concatenate 'string x y))))
et on l'appelle de la manière suivante :
(ma-fonction-add 2 3) renvoie 5
(ma-fonction-add "Toto" "Titi") renvoie "TotoTiti"
De plus, le Lisp est un langage typé (pour ceux qui en doute). on peut soit attendre un type particulier grâce aux asserts ou aider le compilateur grâce à des directives du type
(defun toto (x y)
(declare (type fixnum x y))
bla bla)
Les grands nombres (bignums) sont un autre avantage du Lisp.
Essaye de calculer factoriel 1000 (exemple bateau...) :
(defun fact (n)
(if (= n 1)
1
(* n (fact (1- n)))))
(fact 1000) renvoie un nombre de 2569 chiffres. La seule limite pour n étant la taille de la mémoire.
Bon, je m'arrête là, mais on pourrait aussi parler du système d'exception (thow / catch) ou de CLOS le système objet du Lisp, ou de pleins d'autres notions (memoisation[4]) qui sont tout aussi magnifiques !
Et pour finir, je trouve que le Lisp me permet de faire des programmes de manière simple et rapide tels que je les pense : le langage ne se met pas dans mes pattes et ne m'impose aucune restriction ou obligation sur ce que je devrais faire...
"Greenspun's Tenth Rule of Programming: any sufficiently complicated C or Fortran program contains an ad hoc informally-specified bug-ridden slow implementation of half of Common Lisp." - Philip Greenspun
# Retour d'expériences [long]
Posté par hocwp (site web personnel) . En réponse au journal Lisp et caml. Évalué à 10.
Tout d'abord, le Lisp a une syntaxe extrêmement simple que l'on maîtrise en 10 minutes :
(commande argument1 argument2 argument3)
Un programme en Lisp n'étant qu'une liste d'expressions, on peu manipuler un programme en Lisp comme une donnée quelconque. Ce qui est un avantage pour faire de l'IA (voir le PAIP de Peter Norvig [1] qui est très impressionnant).
Certains critique le trop grand nombre de parenthèses. En fait, elles permettent de délimiter très clairement chaque expression. Par exemple, ce n'est pas nécessaire de connaître l'ordre d'évaluation des différents opérateurs. Comparer :
1+2+3+4+5+6 à (+ 1 2 3 4 5 6)
et 2*3+4*5 à (+ (* 2 3) (* 4 5)).
D'autre part, tout bon éditeur de texte permet de repérer les parenthèses correspondantes et d'indenter correctement le code.
Avec un peu d'habitude, on ne vois plus les parenthèses. De plus, ce qui me manque quand je recode avec d'autres langages, c'est la sélection d'expression : on sélectionne la 1ère parenthèses, on saute à la parenthèse correspondante et on manipule tout le bloc.
Ensuite, le Lisp est très expressif, on utilise en général des noms longs et signifiant ce qu'ils font.
Par exemple: (first '(toto titi plop)) renvoie toto.
Ou pour la gestion des fichiers :
(with-open-file (stream "my-file.txt" :direction :output :if-exists :supersede)
(format stream "j'écris ça dans my-file.txt~%"))
Les macros sont un des gros point fort du Lisp : on peut étendre le langage pour le modeler à ce que l'on veut faire.
Par exemple, je retrouve assez souvent la forme suivante pour la gestion de personnages dans un MUD qui envoi un message à tout les personnages sauf au personnage qui envoi le message :
(dolist (cible (contenu (trouve-contenant perso *monde*)))
(when (and (perso-p cible)
(not (eql cible perso)))
(send-to-perso cible "bla bla bla")
bla bla bla))
plutôt que de répéter (à l'infini et par copier/coller) ce code, j'ai juste écrit la macro suivante :
(defmacro do-for-all-perso ((perso cible) &body body)
`(dolist (,cible (contenu (trouve-contenant ,perso *monde*)))
(when (and (perso-p ,cible)
(not (eql ,cible ,perso)))
,@body)))
maintenant, pour envoyer un message à tout les autres personnages, j'ai juste à écrire :
(do-for-all-perso (cible perso)
(send-to-perso cible "bla bla bla")
bla bla bla)
Les macros sont extrêmement puissantes et permettent d'adapter le langage. Certains les utilisent pour créer des langages spécifiques à leurs domaines d'applications, d'autre par exemple pour avoir la notation infix [2] dans leur programme.
Pour plus de détails sur les macros, la lecture de OnLisp [3] de Paul Graham est un bon point de départ.
Un autre reproche que l'on peut faire au Lisp est qu'il n'a pas de typage statique. Personnellement je trouve que le typage dynamique procure une souplesse très appréciable. Toujours pour l'exemple du MUD, un personnage pourra commencer une partie en tant que simple paysan (la classe paysan) et au cours du jeu acquérir de l'expérience et devenir un magicien (on le change de classe et sa classe devient magicien).
Un autre usage qui revient assez couramment est que l'on peut faire des fonctions qui agirons différemment suivant le type de ces arguments. Exemple :
(defun ma-fonction-add (x y)
(typecase x
(integer (+ x y))
(string (concatenate 'string x y))))
et on l'appelle de la manière suivante :
(ma-fonction-add 2 3) renvoie 5
(ma-fonction-add "Toto" "Titi") renvoie "TotoTiti"
De plus, le Lisp est un langage typé (pour ceux qui en doute). on peut soit attendre un type particulier grâce aux asserts ou aider le compilateur grâce à des directives du type
(defun toto (x y)
(declare (type fixnum x y))
bla bla)
Les grands nombres (bignums) sont un autre avantage du Lisp.
Essaye de calculer factoriel 1000 (exemple bateau...) :
(defun fact (n)
(if (= n 1)
1
(* n (fact (1- n)))))
(fact 1000) renvoie un nombre de 2569 chiffres. La seule limite pour n étant la taille de la mémoire.
Bon, je m'arrête là, mais on pourrait aussi parler du système d'exception (thow / catch) ou de CLOS le système objet du Lisp, ou de pleins d'autres notions (memoisation[4]) qui sont tout aussi magnifiques !
Et pour finir, je trouve que le Lisp me permet de faire des programmes de manière simple et rapide tels que je les pense : le langage ne se met pas dans mes pattes et ne m'impose aucune restriction ou obligation sur ce que je devrais faire...
Enfin, un lien pour démarrer : http://www.algo.be/clr.html
Et une petite citation pour alimenter le troll :
"Greenspun's Tenth Rule of Programming: any sufficiently complicated C or Fortran program contains an ad hoc informally-specified bug-ridden slow implementation of half of Common Lisp." - Philip Greenspun
[1] http://www.norvig.com/paip.html
[2] http://www.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/l(...)
[3] http://www.paulgraham.com/onlisp.html
[4] http://en.wikipedia.org/wiki/Memoisation