Haskell: Où vs.

Je suis nouveau à Haskell et je suis très confus par Where vs. Let . Ils semblent tous deux offrir un objective similaire. J’ai lu quelques comparaisons entre Where vs. Let mais j’ai du mal à savoir quand utiliser chacun d’eux. Quelqu’un pourrait-il s’il vous plaît fournir un contexte ou peut-être quelques exemples qui démontrent quand utiliser l’un sur l’autre?

Où vs. Let

Une clause where ne peut être définie qu’au niveau d’une définition de fonction. Habituellement, cela est identique à la scope de la définition de let . La seule différence est lorsque des gardes sont utilisés . La scope de la clause where s’étend à tous les gardes. En revanche, la scope d’une expression let est uniquement la clause de fonction en cours et guard, le cas échéant.

Haskell Cheat Sheet

Le wiki Haskell est très détaillé et fournit divers cas, mais il utilise des exemples hypothétiques. Je trouve ses explications trop brèves pour un débutant.

Avantages de Let :

 f :: State sa f = State $ \x -> y where y = ... x ... 

Control.Monad.State

ne fonctionnera pas car where fait référence à la correspondance de modèle f =, no x est dans la scope. En revanche, si vous aviez commencé avec let, vous n’auriez pas de problème.

Haskell Wiki sur les avantages de Let

 f :: State sa f = State $ \x -> let y = ... x ... in y 

Avantages de Où :

 fx | cond1 x = a | cond2 x = ga | otherwise = f (hxa) where a = wx fx = let a = wx in case () of _ | cond1 x = a | cond2 x = ga | otherwise = f (hxa) 

Déclaration vs. Expression

Le wiki Haskell mentionne que la clause Where est déclarative tandis que l’expression Let est expressive. Mis à part le style, comment fonctionnent-ils différemment?

 Declaration style | Expression-style --------------------------------------+--------------------------------------------- where clause | let expression arguments LHS: fx = x*x | Lambda abstraction: f = \x -> x*x Pattern matching: f [] = 0 | case expression: f xs = case xs of [] -> 0 Guards: f [x] | x>0 = 'a' | if expression: f [x] = if x>0 then 'a' else ... 
  1. Dans le premier exemple, pourquoi est-ce que Let in scope mais Where is not?
  2. Est-il possible d’appliquer au premier exemple?
  3. Est-ce que certains peuvent appliquer cela à des exemples réels où les variables représentent des expressions réelles?
  4. Y a-t-il une règle générale à suivre quand utiliser chacun?

Mettre à jour

Pour ceux qui viennent par ce fil plus tard, j’ai trouvé la meilleure explication à trouver ici: ” Une introduction douce à Haskell “.

Laissez les expressions.

Les expressions let de Haskell sont utiles chaque fois qu’un ensemble nested de liaisons est requirejs. Comme exemple simple, considérez:

 let y = a*b fx = (x+y)/y in fc + fd 

L’ensemble des liaisons créées par une expression let est mutuellement récursif, et les liaisons de modèle sont traitées comme des motifs paresseux (c’est-à-dire qu’elles portent un ~ implicite). Les seuls types de déclarations autorisés sont les signatures de type, les liaisons de fonction et les liaisons de modèle.

Où Clauses.

Parfois, il est pratique de définir des liaisons sur plusieurs équations protégées, ce qui nécessite une clause where:

 fxy | y>z = ... | y==z = ... | y<z = ... where z = x*x 

Notez que cela ne peut pas être fait avec une expression let qui ne couvre que l’expression qu’elle contient. Une clause where n’est autorisée qu’au niveau supérieur d’un ensemble d’équations ou d’une expression de casse. Les mêmes propriétés et contraintes sur les liaisons dans les expressions let s’appliquent à celles des clauses where. Ces deux formes de scope nestede semblent très similaires, mais rappelez-vous qu’une expression let est une expression, alors qu’une clause where ne l’est pas – elle fait partie de la syntaxe des déclarations de fonctions et des expressions de cas.

1: Le problème dans l’exemple

 f :: State sa f = State $ \x -> y where y = ... x ... 

est le paramètre x . Les éléments de la clause where peuvent uniquement faire référence aux parameters de la fonction f (il n’y en a pas) et aux choses dans les étendues externes.

2: Pour utiliser un where dans le premier exemple, vous pouvez introduire une seconde fonction nommée qui prend le paramètre x comme ceci:

 f = State f' f' x = y where y = ... x ... 

ou comme ça:

 f = State f' where f' x = y where y = ... x ... 

3: Voici un exemple complet sans les ... :

 module StateExample where data State as = State (s -> (a, s)) f1 :: State Int (Int, Int) f1 = State $ \state@(a, b) -> let hypot = a^2 + b^2 result = (hypot, state) in result f2 :: State Int (Int, Int) f2 = State f where f state@(a, b) = result where hypot = a^2 + b^2 result = (hypot, state) 

4: quand utiliser let ou where est une question de goût. J’utilise let pour accentuer un calcul (en le déplaçant vers l’avant) et where mettre l’accent sur le déroulement du programme (en déplaçant le calcul vers l’arrière).

Bien qu’il y ait une différence technique en ce qui concerne les gardes éphémères, il existe également une différence conceptuelle quant à savoir si vous voulez mettre la formule principale en avant avec des variables supplémentaires définies ci-dessous ( where ) ou si vous voulez tout définir formule ci-dessous ( let ). Chaque style a un accent différent et vous voyez les deux utilisés dans les articles de mathématiques, les manuels scolaires, etc. En règle générale, les variables qui ne sont pas suffisamment intuitives pour que la formule n’ait pas de sens sans elles devraient être définies ci-dessus; Les variables intuitives dues au contexte ou à leurs noms doivent être définies ci-dessous. Par exemple, dans l’exemple hashowel d’ephemient, la signification des vowels est évidente et il n’est donc pas nécessaire de la définir au-dessus de son utilisation (sans tenir compte du fait que le garde ne fonctionnerait pas).

Légal:

 main = print (1 + (let i = 10 in 2 * i + 1)) 

Non légal:

 main = print (1 + (2 * i + 1 where i = 10)) 

Légal:

 hasVowel [] = False hasVowel (x:xs) | x `elem` vowels = True | otherwise = False where vowels = "AEIOUaeiou" 

Non légal: (contrairement à ML)

 let vowels = "AEIOUaeiou" in hasVowel = ... 

J’ai trouvé cet exemple de LYHFGG utile:

 ghci> 4 * (let a = 9 in a + 1) + 2 42 

let est une expression pour que vous puissiez mettre n’importe où (!) où les expressions peuvent aller.

En d’autres termes, dans l’exemple ci-dessus, il n’est pas possible d’utiliser simplement pour remplacer let (sans peut-être utiliser une expression de case plus verbeuse combinée avec where ).