Eu sou novo em Haskell e estou muito confuso com Where vs. Let . Ambos parecem fornecer um propósito semelhante. Eu li algumas comparações entre Where vs. Let, mas estou tendo problemas para discernir quando usar cada uma. Alguém poderia fornecer algum contexto ou talvez alguns exemplos que demonstrem quando usar um em vez do outro?
Onde vs. Let
Uma
where
cláusula só pode ser definida no nível da definição de uma função. Normalmente, isso é idêntico ao escopo dalet
definição. A única diferença é quando os guardas estão sendo usados . O escopo dawhere
cláusula se estende a todos os guardas. Em contraste, o escopo de umalet
expressão é apenas a cláusula de função atual e guarda, se houver.
Folha de referências de Haskell
The Haskell Wiki é muito detalhado e fornece vários casos, mas usa exemplos hipotéticos. Acho suas explicações muito breves para um iniciante.
Vantagens do Let :
f :: State s a
f = State $ \x -> y
where y = ... x ...
não funcionará, porque onde se refere ao padrão correspondente f =, onde nenhum x está no escopo. Em contraste, se você tivesse começado com let, não teria problemas.
Haskell Wiki sobre as vantagens do Let
f :: State s a
f = State $ \x ->
let y = ... x ...
in y
Vantagens de onde :
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)
O wiki Haskell menciona que a cláusula Where é declarativa, enquanto a expressão Let é expressiva. Além do estilo, como eles atuam de forma diferente?
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 ...
- No primeiro exemplo, por que o escopo Let está dentro, mas onde não está?
- É possível aplicar Onde ao primeiro exemplo?
- Alguns podem aplicar isso a exemplos reais onde as variáveis representam expressões reais?
- Existe uma regra geral a ser seguida quando usar cada um?
Atualizar
Para aqueles que vêm por este tópico mais tarde, encontrei a melhor explicação a ser encontrada aqui: " Uma introdução gentil a Haskell ".
Let Expressions.
As expressões let de Haskell são úteis sempre que um conjunto aninhado de ligações é necessário. Como um exemplo simples, considere:
let y = a*b f x = (x+y)/y in f c + f d
O conjunto de associações criadas por uma expressão let é mutuamente recursiva e as associações de padrão são tratadas como padrões preguiçosos (ou seja, carregam um ~ implícito). Os únicos tipos de declarações permitidas são assinaturas de tipo, associações de função e associações de padrão.
Onde Cláusulas.
Às vezes, é conveniente definir o escopo das ligações em várias equações protegidas, o que requer uma cláusula where:
f x y | y>z = ... | y==z = ... | y<z = ... where z = x*x
Observe que isso não pode ser feito com uma expressão let, que abrange apenas a expressão que ela inclui. Uma cláusula where só é permitida no nível superior de um conjunto de equações ou expressão case. As mesmas propriedades e restrições sobre ligações em expressões let se aplicam àquelas em cláusulas where. Essas duas formas de escopo aninhado parecem muito semelhantes, mas lembre-se de que uma expressão let é uma expressão, enquanto uma cláusula where não é - ela é parte da sintaxe de declarações de função e expressões case.
let
ewhere
quando comecei a aprender Haskell. Acho que a melhor maneira de entender isso é perceber que há muito pouca diferença entre os dois e, portanto, nada com que se preocupar. O significado dewhere
dado em termos delet
uma transformação mecânica muito simples. Veja haskell.org/onlinereport/decls.html#sect4.4.3.2 Essa transformação existe apenas para conveniência de notação, na verdade.f = body where x = xbody; y = ybody ...
significaf = let x = xbody; y = ybody ... in body
case .... of ... where
expressão de alguma forma? Eu não tenho certeza sobre isso.Respostas:
1: O problema no exemplo
é o parâmetro
x
. Coisas nawhere
cláusula podem se referir apenas aos parâmetros da funçãof
(não há nenhum) e coisas em escopos externos.2: Para usar a
where
no primeiro exemplo, você pode introduzir uma segunda função nomeada que leva ox
como um parâmetro, como este:ou assim:
3: Aqui está um exemplo completo sem o
...
's:4: Quando usar
let
ouwhere
é uma questão de gosto. Eu usolet
para enfatizar um cálculo (movendo-o para a frente) ewhere
para enfatizar o fluxo do programa (movendo o cálculo para trás).fonte
Embora haja uma diferença técnica em relação aos guardas que aquele efemiente apontou, também há uma diferença conceitual se você deseja colocar a fórmula principal antecipadamente com as variáveis extras definidas abaixo (
where
) ou se você deseja definir tudo antecipadamente e colocar a fórmula abaixo (let
). Cada estilo tem uma ênfase diferente e você vê ambos usados em trabalhos de matemática, livros didáticos, etc. Geralmente, variáveis que são suficientemente não intuitivas para que a fórmula não faça sentido sem elas devem ser definidas acima; variáveis que são intuitivas devido ao contexto ou seus nomes devem ser definidas a seguir. Por exemplo, no exemplo hasVowel do ephemient, o significado devowels
é óbvio e por isso não precisa ser definido acima de seu uso (desconsiderando o fato de quelet
não funcionaria devido ao guarda).fonte
Legal:
Não é legal:
Legal:
Não legal: (ao contrário de ML)
fonte
hasVowel = let^M vowels = "AEIOUaeiou"^M in ...
(^M
é nova linha)Achei este exemplo do LYHFGG útil:
let
é uma expressão para que você possa colocar um emlet
qualquer lugar (!) onde as expressões possam ir.Em outras palavras, no exemplo acima, não é possível usar
where
para simplesmente substituirlet
(sem talvez usar algumacase
expressão mais detalhada combinada comwhere
).fonte
Infelizmente, a maioria das respostas aqui é muito técnica para um iniciante.
LHYFGG tem um capítulo relevante sobre isso - que você deve ler se ainda não o fez, mas em essência:
where
é apenas uma construção sintática (não um açúcar ) que é útil apenas em definições de funções .let ... in
é uma expressão em si , portanto, você pode usá-los onde quer que coloque uma expressão. Sendo uma expressão em si, não pode ser usado para amarrar coisas para guardas.Por último, você também pode usar
let
em compreensões de lista:fonte