• [^] # Re: C'est bien dommage

    Posté par . En réponse au journal C++17 est sur les rails. Évalué à 1.

    Par contre la macro est évaluée au moment de la compilation, donc une seule fois.

    Il reste juste à noter que cette macro est assez simple mais qu'elle pourrait faire des calculs complexes, parcourir les expressions qu'on lui passe en paramètre (il s'agit de simples listes), faire n'importe quoi pour générer le code Lisp destiné à la remplacer. Il s'agit simplement de code Lisp quelconque manipulant des listes (parcours, construction, ...).

    Est-ce que c'est plus clair ?

    Oui c'est plus clair, je n'avais pas fait attention à ta remarque qui expliquait que les macros étaient exécutées à la compilation (ce qui explique leur dénomination).

    En fait le compilateur OCaml fait la même chose avec certaines fonctions, et dans la nouvelle version à venir il le généralise via une nouvelle représentation intermédiaire, qui ne sera qu'optionnelle pour cette version, mais sera sans aucun doute la base pour les versions ultérieures. Par exemple le compilateur actuel remplace systématiquement les appels à ma fonction iff par if b then e1 else e2 (comme si c'était une macro en Common Lisp), mais le nouveau système pousse l'idée plus loin en l'étendant aux fonctions récursives et en « exécutant » au maximum le code de la fonction qu'il développe. Tu pourras en lire plus sur la partie que j'ai consacré, avec chicco, au système FLambda dans la dépêche en cours de rédaction.

    Sinon if est aussi une primitive en OCaml, comme en Common Lisp, mais n'est en fait qu'un cas particulier d'une autre structure primitive le pattern matching qui est une version généralisée de ta macro cond : if b then e1 else e2 n'est qu'un alias pour match b with true -> e1 | false -> e2, et on peut mettre autant de cas que l'on veut dans l'analyse et pas seulement en faisant des tests sur les booléens mais sur la forme et la structure du type que l'on étudie. Cela parce que, comme pour Common Lisp, toutes les valeurs sont essentiellement des références (sauf les types int, bool, char et les constructeurs constants comme la liste vide) et accessible uniquement via leur constructeur de type.

    Par exemple pour définir la fonction list_map qui applique une fonction à tous les éléments d'une liste, on l'écrira

    (* en OCaml le type des listes se définit comme *)
    type 'a list =
     | Nil (* la liste vide *)
     | Cons of 'a * 'a list (* le nom du constructeur est issu du nom de l'opérateur en Lisp ;-) *)
    (* [] est un alias pour la liste vide et hd :: tl un alias pour Cons(hd, tl) 
    la liste [1; 2; 3] se construit par Cons(1, Cons(2, Cons(3, Nil))) et on retrouve la structure de liste imbriquée à la Lisp *)
    let rec list_map f l =
     match l with
     (* soit la liste est vide et on renvoie la liste vide *)
     | [] -> []
     (* soit elle a une tête et une queue, alors on applique f à la tête et list_map à la queue *)
     | hd :: tl -> (f hd ) :: (list_map f tl)
    ;;
    (* on peut alors faire une fonction qui renvoie la liste des successeurs d'une liste d'entiers *)
    let succ_list l = list_map (fun n -> n + 1) l;;
    (* mais à la compilation il va développer list_map comme une macro et simplifier le tout en *)
    let succ_list l =
     let rec list_map' l =
     match l with
     | [] -> []
     | hd :: tl -> (hd + 1) :: (list_map' tl)
     in list_map' l
    ;;

    Sinon pour la coloration de code en Common Lisp, je mets lisp comme langage.

    (defmacro if (condition expr1 expr2)
     `(cond
     (,condition
     ,expr1)
     (t
     ,expr2)))

    Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.