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

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

    D'accord, si je comprends bien ce qui distingue une fonction d'une macro c'est le mode d'évalution des paramètres : pour une fonction ils sont passés par valeur, là où pour une macro ils sont passés par nom (dans ce cas l'évaluation est-elle paresseuse, i.e évalué une seule fois à la première utilisation du terme, ou recalculer à chaque usage du terme ?).

    Par curiosité, dans ton exemple en OCaml tu écris ça :

    (* je code le test if-then-else en fonctionnel pure *)
    let iff b e1 e2 = if b then e1 else e2

    Dans un langage comme Java ça ne marche pas parce que les expressions e1 et e2 seraient évaluées systématiquement avant d'être passées en paramètre à la fonction iff.
    En Common Lisp ça marche si iff est une macro, ce qui permet de ne pas évaluer systématiquement les deux expressions avant de choisir le résultat à renvoyer.
    En OCaml ça marche parce que le langage est purement fonctionnel et que le compilateur va se débrouiller pour n'évaluer que les expressions nécessaires ? Ou tu as fait un exemple simplifié ?

    Comme l'a dit anaseto, en OCaml les paramètres sont passés par valeur, ils sont évalués par l'appelant avant d'être passés à la fonction appelée (à la manière des fonctions Lisp et non des macros). La seule exception concerne les opérateurs sur les booléens : && (et) et || (ou) qui sont évalués de gauche à droite et de façon paresseuse. Cela étant en Comme Lisp if est une macro ou une fonction ?

    Comme l'a aussi précisé anaseto, il est possible de faire de l'évaluation paresseuse en OCaml via le module Lazy. Le même exemple (factoriel) avec iff en mode macro :

    let le = ( <= ) and mul = ( * ) and minus = ( - );;
    val le : 'a -> 'a -> bool = <fun>
    val mul : int -> int -> int = <fun>
    val minus : int -> int -> int = <fun>
    (* maintenant iff n'évalue que e1 ou que e2 suivant la valeur du booléen *)
    let iff b e1 e2 = if b then Lazy.force e1 else Lazy.force e2
    val iff : bool -> 'a lazy_t -> 'a lazy_t -> 'a = <fun>
    let rec factorial ?(acc=1) n =
     (iff (le n 1)
     (lazy acc)
     (lazy (factorial ~acc:(mul acc n) (minus n 1)))) (* on pourrait utiliser (pred n) au lieu de (minus n 1) *)
    val factorial : ?acc:int -> int -> int = <fun>
    factorial 5;;
    - : int = 120

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