Journal Lisp et caml

Posté par  (site web personnel) .
Étiquettes : aucune
0
17
déc.
2005
Bonsoir, j'ai quelques difficultés (peut être parce que je maîtrise assez mal ces deux langages) à comprendre les intérêts respectifs de ces deux langages, sachant qu'ils se ressemblent sur pas mal d'aspect.

J'ai beaucoup plus pratiqué Caml, et a priori, Lisp ne possède pas le typage fort de OCaml/Camllight

Dans cette doc http://www.algo.be/cl/TEE-lisp/318639977372240/index.htm , je trouve un algo de base que je traduirai ainsi en caml :

(DEFUN SORT-ELEMENTS-BY-INDEX (ELEMENTS WAVELENGTH)
(SORT
ELEMENTS
#'(LAMBDA (ELEMENT-1 ELEMENT-2)
(< (ELEMENT-REFRACTIVE-INDEX ELEMENT-1 WAVELENGTH)
(ELEMENT-REFRACTIVE-INDEX ELEMENT-2 WAVELENGTH)))))

deviendrait

let rec sort_el_by_idx = function elem, wavelenght ->
sort elem , y
and y wavelenght = function el1, el2 ->
if (elem_refract_idx el1,wavelenght) < (elem_refract_idx el2,wavelenght) then el1 else el2;;

J'utilise un exemple simple, mais je vois mal en quoi ces langages diffèrent, et en quoi l'un a quelques avantages ou désavantages sur l'autre ? Pourquoi me dit-on que Lisp est entre autre fait pour faire de l'IA, purquoi Lisp plus que caml ? Etc...

N'y connaissant pas assez, j'ose à peine dire que ma préférence va à Caml, mais certains auront peut être des témoignages intéressants.

Trollomètre activé !
  • # Auto-manipulation

    Posté par  (Mastodon) . Évalué à 10.

    Un des avantages de Lisp, c'est que le langage manipule des listes ET le programme est une liste. Donc tu peux faire très facilement un programme qui manipule du code, ou qui se manipule lui même. C'est essentiellement pour ça que c'est pratique en IA.

    Les macros de Lisp sont très sympas, et n'ont pas grand chose à voir avec les macros dans les autres langages, mais je ne me sens pas capable de détailler et je te renvoie vers les bouquins de Lisp :)

    L'avantage d'OCaml, c'est que c'est rapide, et que l'inférence de type élimine une partie des erreurs qui seraient parfois difficiles à trouver avec un typage dynamique ou faible.
  • # Retour d'expériences [long]

    Posté par  (site web personnel) . Évalué à 10.

    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 :

    (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
  • # Plutôt caml

    Posté par  . Évalué à 3.

    J'ai utilisé ocaml assez souvent, ms il y a déjà un petit bout de temps.
    J'ai très peu fait de lisp, un peu plus de scheme

    J'utilise un exemple simple, mais je vois mal en quoi ces langages diffèrent,
    Je dirais que ocaml fait du typage statique, avec inférence de type
    alors que lisp fait du typage dynamique.

    La syntaxe de ocaml à mois de parenthèses ;)
    Je pense que ocaml est peut-être plus lisible, mais la syntaxe régulière de lisp permet des choses intéressante sur les S-expressions.

    ocaml peut-être compilé en natif ou en bytecode. c'est surement vrai aussi pour lisp, mais il y a bcp de compilateur/interpreteurs différent, et je ne prétends pas les connaître tous.

    Un truc sympa en ocaml c'est les types sommes, utilisés conjointement avec le pattern matching: le code reflète la structure de donnée. C'est aussi possible en lisp, ms je trouve que la definition des type est moins évidente, et que le pattern matching est moins facile à réaliser.



    Pourquoi me dit-on que Lisp est entre autre fait pour faire de l'IA, purquoi Lisp plus que caml ? Etc...
    Je pense que c'est surtout pour des raison historique. lisp est un langage très souple et les S-expression un moyen commode de representer des donnée de manières générique. De je ne crois pas dire de bétise en disant que lisp est un des premier langage à proposer des fonctionnalités objet.
    Cependant j'ai justement utilisé ocaml dans le cadre de l'IA (pendant mes étude) et c'est très valable. Et aujourd'hui si je veux un langage dynamique, j'utilise plutôt Python ou Smalltalk (et Ruby que j'essaye en ce moment pour m'amuser)


    N'y connaissant pas assez, j'ose à peine dire que ma préférence va à Caml, mais certains auront peut être des témoignages intéressants.
    J'ai aussi tendance à préferer ocaml à lisp.
    Même si j'avoue avoir eu du mal au début à satisfaire le systême de typage: ça a mis en lumière le fait que je commençais svt à coder avent de savoir précisément quoi coder: typer une fonction implique souvent de spécifier le comportement exact attendu.

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.