[Haskell] Lumière sur la construction 'let ... in'

Ou sa "sémantique"

Source - le Ven 27 janvier à 19:35:06

Bonsoir,

Je m'interroge à propos de la construction 'let ... in', voici d'abord un code pour illustrer ma question qui suivra :

   --

   -- espace pour pas mordre l'avatar

f x = x^3 - 5*x^2 + 20

integr min max prec = if min >= max then 0 else
    let dx = (max-min/prec) in
        ((f min) * dx) + integr (min+dx) max prec

Il faudrait que la variable dx soit définie une seule fois, lors des valeurs initiales de min et max, d'où la question : la construction 'let ... in' a-t-elle pour effet de définir dx une seule fois ou alors elle ré-actualise dx à chaque itération ?

Le site de Haskell ne semble pas répondre à cette question : http://www.haskell.org/haskellwiki/Keywords#let (ou alors ne s'agit-il pas du même let ?) hélas.

Réponses qui ont aidé l'auteur

8 réponse(s)

gasche # - le Ven 27 janvier à 21:35:45 - Répondre - Source - Cette réponse a aidé l'auteur du sujet
Avatar

Le code let x = e1 in e2 a le même sens quel que soit le contexte; Haskell n'a pas idée de "chaque itération" ou "une seule fois". Le résultat de let x = e1 in e2 est le même que le résultat de e2, dans lequel x a été remplacé par e1. Cela veut dire que ton code fournira le même résultat que :

integr min max prec = if min >= max then 0 else
  ((f min) * (max-min/prec)) + integr (min + (max-min/prec)) max prec

(Le résultat est le même, par contre le temps de calcul peut être différent: avec le let, en général dx n'est évalué qu'une seule fois au lieu d'être recalculé à chaque endroit où il est utilisé. Ici ça ne change rien puisque le compilateur va optimiser et ré-écrire dans tous les sens de toute façon).

PS: tu ne voulais pas plutôt écrire (max-min)/prec ?

grand d'esprit # - le Ven 27 janvier à 22:01:21 - Répondre - Source
Avatar

Si, je voulais en effet écrire (max-min)/prec, j'ai pas fais gaffe avec l'auto-complétion des parenthèses :-°

Merci pour ces éclaircissements, mais dans ce cas y aurait-il un moyen de définir une sorte de constante ? C'est la première fois que je suis confronté à ce problème, d'apparence plutôt banal...

Et une autre chose me pose problème, est-ce que ces deux constructions suivantes sont équivalentes :

 let a1 in a2
-- et
 a2 where a1

Un exemple plus concret :

fun x = let a = x+x in
    a

fun x = a
    where a = x+x

J'avais, à la base, pensé que la construction 'let' avait justement le comportement que j'ai décrit à tord dans le topic, ce qui me permettait de différencier le 'let' du 'where'.

gasche # - le Sam 28 janvier à 00:36:13 - Répondre - Source - Cette réponse a aidé l'auteur du sujet
Avatar

let et where sont équivalents. Pour faire ce que tu veux, il faut réorganiser ton programme. Par exemple tu pourrais avoir une fonction integrale non-récursive qui calcule le dx global, et qui appelle une sous-fonction récursive (ou autre technique) pour calculer la somme.

grand d'esprit # - le Sam 28 janvier à 09:30:27 - Répondre - Source
Avatar

Voici ce que je fais, ça marche parfaitement et c'est encore plus précis que ma TI :

integr a b prec = let dx = (b-a)/prec in
    subIntegr a b dx
        where subIntegr a b dx = if a >= b then 0 else
                (f a) * dx + subIntegr (a+dx) b dx

Je vais rajouter un argument qui est une fonction, ça sera plus commode à utiliser.

Je viens de me rendre compte que l'ancienne fonction était récursive infiniment, même si il y avait une récursion finale. Le pas dx diminuant à chaque fois, il était impossible pour min d'atteindre max un jour... On avait une asymptote en y = max (c'est comme ça qu'on dit ?).

En tous cas merci gasche pour ton aide.

gasche # - le Sam 28 janvier à 09:52:01 - Répondre - Source
Avatar

Une dernière remarque: comme dx est constant pendant les appels à subIntegr, et déjà dans l'environnement, tu n'es pas obligé de le passer en paramètre.

grand d'esprit # - le Sam 28 janvier à 09:59:50 - Répondre - Source
Avatar

D'accord, je corrige ça. Merci.

Ptival # - le Sam 28 janvier à 10:17:36 - Répondre - Source - Cette réponse a aidé l'auteur du sujet
Avatar

Citation de gasche

let et where sont équivalents.

Pas exactement, et c'est justement pourquoi grand d'esprit a dû passer dx ici, car sa portée s'arrête à la sous-expression dans le in.

Deux solutions simples : changer le where en let, ou le let en where. Par exemple :

integr f a b prec = subIntegr a b
    where
        subIntegr a b = if a >= b
                        then 0
                        else (f a) * dx + subIntegr (a + dx) b
        dx = (b - a) / prec
gasche # - le Sam 28 janvier à 10:39:18 - Répondre - Source
Avatar

Mouais, ça c'est des mochetés de la syntaxe Haskell (la façon dont where est défini est assez dégueu), mais la sémantique est la même.

Répondre à "[Haskell] Lumière sur la construction 'let ... in'"

Vous devez être connecté pour poster.