functions - if en haskell ejemplos
Haskell: donde vs. (4)
Soy nuevo en Haskell y estoy muy confundido con Where vs. Let . Ambos parecen proporcionar un propósito similar. He leído algunas comparaciones entre Where vs. Let, pero tengo problemas para discernir cuándo usar cada una. ¿Podría alguien proporcionar algún contexto o quizás algunos ejemplos que demuestren cuándo usar uno sobre el otro?
Donde vs.
Una cláusula
where
solo se puede definir en el nivel de una definición de función. Por lo general, eso es idéntico al alcance delet
definition. La única diferencia es cuando se usan guardias . El alcance de la cláusulawhere
extiende a todos los guardias. Por el contrario, el alcance de una expresiónlet
es solo la cláusula de función actual y guard, si hay alguno.
La Wiki Haskell es muy detallada y proporciona varios casos, pero utiliza ejemplos hipotéticos. Encuentro sus explicaciones demasiado breves para un principiante.
Ventajas de Let :
f :: State s a
f = State $ /x -> y
where y = ... x ...
no funcionará, porque donde se refiere al patrón que coincide con f =, donde no x está en el alcance. Por el contrario, si hubieras comenzado con let, entonces no tendrías problemas.
Haskell Wiki sobre las ventajas de Let
f :: State s a
f = State $ /x ->
let y = ... x ...
in y
Ventajas de Dónde :
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)
La wiki de Haskell menciona que la cláusula Where es declarativa mientras que la expresión Let es expresiva. Aparte del estilo, ¿cómo se comportan de manera 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 ...
- En el primer ejemplo, ¿por qué el alcance de entrada es Where is not?
- ¿Es posible aplicar Dónde al primer ejemplo?
- ¿Pueden algunos aplicar esto a ejemplos reales donde las variables representan expresiones reales?
- ¿Hay una regla general a seguir cuando usar cada uno?
Actualizar
Para aquellos que vengan más tarde a este hilo, encontré la mejor explicación que se puede encontrar aquí: " Una introducción suave a Haskell ".
Let Expressions.
Las expresiones de let de Haskell son útiles siempre que se requiera un conjunto anidado de enlaces. Como un simple ejemplo, considere:
let y = a*b f x = (x+y)/y in f c + f d
El conjunto de enlaces creado por una expresión let es mutuamente recursivo, y los enlaces de patrón se tratan como patrones perezosos (es decir, llevan un ~ implícito). El único tipo de declaraciones permitidas son firmas de tipo, enlaces de función y enlaces de patrón.
Donde Cláusulas.
A veces es conveniente realizar enlaces a varias ecuaciones protegidas, lo que requiere una cláusula where:
f x y | y>z = ... | y==z = ... | y<z = ... where z = x*x
Tenga en cuenta que esto no se puede hacer con una expresión let, que solo abarca la expresión que encierra. Una cláusula where solo está permitida en el nivel superior de un conjunto de ecuaciones o expresión de caso. Las mismas propiedades y restricciones en los enlaces en las expresiones de let se aplican a aquellos en las cláusulas where. Estas dos formas de ámbito anidado parecen muy similares, pero recuerde que una expresión let es una expresión, mientras que una cláusula where no lo es, es parte de la sintaxis de declaraciones de funciones y expresiones de casos.
1: El problema en el ejemplo
f :: State s a
f = State $ /x -> y
where y = ... x ...
es el parámetro x
. Las cosas en la cláusula where
pueden referirse solo a los parámetros de la función f
(no hay ninguno) y cosas en ámbitos externos.
2: para usar a where
en el primer ejemplo, puede introducir una segunda función nombrada que toma la x
como un parámetro, como este:
f = State f''
f'' x = y
where y = ... x ...
o así:
f = State f''
where
f'' x = y
where y = ... x ...
3: Aquí hay un ejemplo completo sin los ...
''s:
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: Cuándo usar let
o where
es una cuestión de gusto. Utilizo let
para enfatizar un cálculo (moviéndolo al frente) y where
enfatizar el flujo del programa (moviendo el cálculo hacia atrás).
Encontré este ejemplo de LYHFGG útil:
ghci> 4 * (let a = 9 in a + 1) + 2
42
let
es una expresión para que puedas poner en cualquier lugar (!) donde puedan ir las expresiones.
En otras palabras, en el ejemplo anterior no es posible usar where
simplemente reemplazar let
(sin quizás usar alguna expresión de case
más detallada combinada con where
).
Legal:
main = print (1 + (let i = 10 in 2 * i + 1))
Ilegal:
main = print (1 + (2 * i + 1 where i = 10))
Legal:
hasVowel [] = False
hasVowel (x:xs)
| x `elem` vowels = True
| otherwise = False
where vowels = "AEIOUaeiou"
No es legal: (a diferencia de ML)
let vowels = "AEIOUaeiou"
in hasVowel = ...
Si bien existe una diferencia técnica con respecto a los guardias que ephemient señaló, también hay una diferencia conceptual en si desea colocar la fórmula principal por adelantado con las variables adicionales definidas a continuación ( where
) o si desea definir todo por adelantado y poner el fórmula a continuación ( let
). Cada estilo tiene un énfasis diferente y se ven ambos utilizados en documentos de matemáticas, libros de texto, etc. En general, las variables que son lo suficientemente intuitivas como para que la fórmula no tenga sentido sin ellas deberían definirse anteriormente; las variables que son intuitivas debido al contexto o sus nombres se deben definir a continuación. Por ejemplo, en el ejemplo de ephemient hasVowel, el significado de las vowels
es obvio y por lo tanto no es necesario definirlo por encima de su uso (sin tener en cuenta el hecho de que let
no funciona debido a la guardia).