Je suis nouveau à Haskell et je suis très confus par Où vs Soit . Ils semblent tous deux fournir un objectif similaire. J'ai lu quelques comparaisons entre Où vs Soit mais je suis avoir du mal à discerner quand les utiliser. Quelqu'un pourrait-il s'il vous plaît fournir un certain contexte ou peut-être quelques exemples qui 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 portée de la définition delet
. La seule différence est lorsque les gardes sont utilisés. La portée de la clausewhere
s'étend à toutes les protections. En revanche, la portée d'une expressionlet
n'est que la clause de fonction actuelle et la garde, le cas échéant.
Le Haskell Wiki 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 s a
f = State $ \x -> y
where y = ... x ...
ne fonctionnera pas, car où fait référence au modèle correspondant à f =, où aucun x n'est dans la portée. En revanche, si vous aviez commencé avec let, vous n'auriez aucun problème.
Wiki Haskell sur les avantages de Let
f :: State s a
f = State $ \x ->
let y = ... x ...
in y
Avantages de Where :
f x
| cond1 x = a
| cond2 x = g a
| otherwise = f (h x a)
where
a = w x
f x
= let a = w x
in case () of
_ | cond1 x = a
| cond2 x = g a
| otherwise = f (h x a)
Le wiki Haskell mentionne que la clause Where est déclarative tandis que l'expression Let est expressif. Mis à part le style, comment fonctionnent-ils différemment?
Declaration style | Expression-style
--------------------------------------+---------------------------------------------
where clause | let expression
arguments LHS: f x = 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 ...
Pour ceux qui viendront par ce fil plus tard, j'ai trouvé la meilleure explication ici: " A Gentle Introduction to Haskell ".
Soit Expressions.
Les expressions let de Haskell sont utiles chaque fois qu'un ensemble de liaisons imbriquées est requis. À titre d'exemple simple, considérez:
let y = a*b f x = (x+y)/y in f c + f d
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 modèles paresseux (c'est-à-dire qu'ils portent un ~ implicite). Les seuls types de déclarations autorisés sont les signatures de type, les liaisons de fonctions et les liaisons de modèles.
Où les clauses.
Parfois, il est pratique d'étendre les liaisons sur plusieurs équations protégées, ce qui nécessite une clause where:
f x y | 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'expressions 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 portée imbriquée 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 fonction et des expressions case.
1: Le problème dans l'exemple
f :: State s a
f = State $ \x -> y
where y = ... x ...
est le paramètre x
. Les éléments de la clause where
ne peuvent faire référence qu'aux paramètres de la fonction f
(il n'y en a pas) et aux éléments des étendues externes.
2: Pour utiliser un where
dans le premier exemple, vous pouvez introduire une deuxième fonction nommée qui prend le x
comme paramètre, 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 le ...
:
module StateExample where
data State a s = 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 souligner un calcul (en le déplaçant vers l'avant) et where
pour souligner le flux du programme (en déplaçant le calcul vers l'arrière).
Bien qu'il y ait la différence technique en ce qui concerne les gardes que l'éphémient a souligné, il y a aussi une différence conceptuelle entre le fait de vouloir mettre la formule principale à l'avance avec des variables supplémentaires définies ci-dessous (where
) ou si vous voulez définir tout à l'avance et mettez la formule ci-dessous (let
). Chaque style a une emphase différente et vous les voyez tous les deux utilisés dans les articles de mathématiques, les manuels, etc. En général, les variables qui ne sont pas suffisamment intuitives pour que la formule n'a pas de sens sans elles devraient être définies ci-dessus; les variables intuitives en raison du contexte ou de leurs noms doivent être définies ci-dessous. Par exemple, dans l'exemple hasVowel de l'éphémient, la signification de 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 let
ne fonctionnerait pas à cause du gardien).
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, vous pouvez donc mettre un let
n'importe où (!) où les expressions peuvent aller.
En d'autres termes, dans l'exemple ci-dessus, il n'est pas possible d'utiliser where
pour remplacer simplement let
(sans peut-être en utilisant une expression case
plus verbeuse combinée avec where
).