• [^] # Re: lim_t→∞lang(t) = Common Lisp

    Posté par . En réponse à la dépêche Le langage D 1.00 est disponible !. Évalué à 10.

    C'est clair que les fonctionnalités sont clairement bien en deçà de celle de LISP (ou de ses dialectes). Je suis étonné du nombre de langages qui fleurissent et dont les "nouveautés" sont beaucoup moins bonnes que l'état de l'art dans des systèmes moins connus ou sont tout simplement des choses qui devraient faire partie de la bibliothèque et pas du langage.

    Exemple ici :

    * templates : un mécanisme à pleurer quand on a un minimum joué avec des systèmes de modules paramétrés comme ceux de SML ou d'Objective Caml ou même tout simplement quand on a utilisé un langage avec des fonctions polymorphes (ML et l'essentiel des langages typés dynamiquement).

    * tableaux dynamiques : devraient faire partie de la bibliothèque du langage, pas du langage lui-même (pour la syntaxe, les macros de LISP permettent de faire ça très bien, on peut s'en sortir également très facilement en Caml)

    * "scope guards" : typiquement un truc qui se fait en 3 lignes de code de bibliothèque. En O'Caml le code pour l'équivalent du try finally présenté donne la chose suivante :

    let abc() =
    let m = Mutex.create() in (* un peu bizarre de faire un mutex localement, a priori, il devrait plutôt être une variable globale, mais bon *)
    Mutex.lock(m);
    try foo() with e -> (Mutex.unlock(m); raise e)
    Mutex.unlock(m)

    Maintenant je m'aperçois que ce motif revient un peu trop souvent. Comment faire mieux ? C'est tout simple, il suffit d'écrire le motif en paramétrant par foo :

    let with_lock f =
    let m = Mutex.create() in
    Mutex.lock(m);
    try f() with e -> (Mutex.unlock(m); raise e)
    Mutex.unlock(m)

    Et je peux maintenant écrire abc en une ligne :
    let abc() = with_lock foo

    Si "foo" est un block de code et non une fonction prenant () en argument, on utilise une simple fonction anonyme :

    let abc() = with_lock (fun () -> begin
    Printf.printf "Hello world\n";
    Printf.printf "Hello DLFP\n";
    end)

    À côté de cela, on retrouve en D les unions du C (je n'ai pas testé, mais ça a bien l'air d'être ça) alors que clairement, les types sommes qu'on trouve en ML (depuis plus de 20 ans) sont extrêmement utiles. Les types sommes, c'est tout simplement des types unions dans lesquels on peut savoir quelle variante de l'union on a prise.

    Ex en Caml :

    type figure = Roi | Dame | Valet (* là, c'est juste un type énuméré *)
    type carte = Valeur of int | Figure of figure (* une union de figure et int, avec une étiquette (Valeur ou Figure) pour dire dans quel cas on est *)

    Mettons qu'on donne au roi la valeur 4, aux autres figures la valeur 0 et aux cartes numérotées le nombre qui y est inscrit. On peut calculer ça comme suit :

    let valeur carte = match carte with
    | Valeur n ->
    | Figure Roi -> 4
    | Figure _ -> 0

    Cet exemple est évidemment inintéressant mais dès qu'on fait un peu d'algorithmique, il est très pratique de manipuler des structures de données ou une valeur peut être une feuille ou un noeud...

    Un des problèmes avec LISP (ou ses variantes comme Scheme), et ML (et ses variantes SML, Objective Caml, ...) est qu'il faut accepter de rentrer dans un modèle qui a été pensé au départ par des théoriciens, universitaires de surcroît (quelle tare !). Pour ma part, je suis tombé dans la marmite dans mon jeune âge mais, bien qu'étant curieux, je n'ai encore pas trouvé de langage équivalent à ceux de cette famille... (pour être précis, les langages plus connus ont des avantages en termes de bibliothèques, d'environnement de développement, mais les langages en eux-mêmes sont nettement, nettement moins fun...)