tipos sumatoria sintaxis imprimir funciones ejemplos datos ciclos basico basicas basica haskell scope whitespace where-clause let

sintaxis - sumatoria en haskell



En Haskell, ¿cuándo usamos adentro con let? (4)

Algunas notas para principiantes sobre "están siguiendo dos iguales".

Por ejemplo, add1 es una función que agrega 1 al número:

add1 :: Int -> Int add1 x = let inc = 1 in x + inc

Por lo tanto, es como add1 x = x + inc con la sustitución inc por 1 de la palabra clave let .

Cuando intentas suprimir in palabra clave

add1 :: Int -> Int add1 x = let inc = 1 x + inc

tienes un error de análisis

De la documentation :

Within do-blocks or list comprehensions let { d1 ; ... ; dn } without `in` serves to introduce local bindings.

Por cierto, hay una buena explicación con muchos ejemplos sobre lo where realmente hacen y in palabra clave.

En el siguiente código, la última frase que puedo poner al frente. ¿Cambiará algo?

Otra pregunta: si decido ponerme in frente de la última frase, ¿debo sangrarla?

Intenté sin sangrar y abrazos quejas

El último generador en do {...} debe ser una expresión

import Data.Char groupsOf _ [] = [] groupsOf n xs = take n xs : groupsOf n ( tail xs ) problem_8 x = maximum . map product . groupsOf 5 $ x main = do t <- readFile "p8.log" let digits = map digitToInt $concat $ lines t print $ problem_8 digits

Editar

Ok, entonces la gente parece no entender lo que estoy diciendo. Permítanme reformular: ¿son los dos siguientes lo mismo, dado el contexto anterior?

1.

let digits = map digitToInt $concat $ lines t print $ problem_8 digits

2.

let digits = map digitToInt $concat $ lines t in print $ problem_8 digits

Otra pregunta sobre el alcance de las consolidaciones declaradas en let : Leí here que:

where 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 .

Mi pregunta: entonces, los dígitos variables no deberían estar visibles para la última frase impresa. ¿Extraño algo aquí?


En la notación do , puedes usar let con y sin in . Para que sea equivalente (en su caso, mostraré más adelante un ejemplo en el que necesita agregar un segundo do y por lo tanto más sangrado), debe aplicar una sangría como descubrió (si usa el diseño, si usa llaves y puntos y coma explícitos, son exactamente equivalentes).

Para entender por qué es equivalente, debes asimilar mónadas (al menos hasta cierto punto) y observar las reglas deslumbrantes para la notación do . En particular, código como este:

do let x = ... stmts -- the rest of the do block

se traduce para let x = ... in do { stmts } . En su caso, stmts = print (problem_8 digits) . Evaluar todo el desajuste let resultados vinculantes en una acción IO (desde print $ ... ). Y aquí, necesita una comprensión de las mónadas para acordar intuitivamente que no hay diferencia entre las anotaciones de do y los elementos de lenguaje "regulares" que describen un cálculo que da como resultado valores monádicos.

En cuanto a ambos, ¿por qué son posibles? Bueno, let ... in ... tiene una amplia gama de aplicaciones (la mayoría de las cuales no tienen nada que ver con las mónadas en particular), y una larga historia para arrancar. por otra parte, let sin para do notación, parece ser nada más que una pequeña pieza de azúcar sintáctica. La ventaja es obvia: puede vincular los resultados de cálculos puros (como en, no monádicos) a un nombre sin recurrir a un val <- return $ ... sin sentido y sin dividir el bloque do en dos:

do stuff let val = ... in do more stuff $ using val

La razón por la que no necesitas un bloque do adicional para lo que sigue al let es que solo tienes una línea. Recuerde, do e e .

En cuanto a tu edición: el digit se ve en la siguiente línea es el punto completo. Y no hay excepción para eso ni nada. do notación do convierte en una sola expresión, y let funcione bien en una sola expresión. where solo se necesita para cosas que no son expresiones.

Por el bien de la demostración, mostraré la versión desacralizada de tu bloque do . Si aún no está muy familiarizado con las mónadas (algo que debe cambiar pronto en mi humilde opinión), ignore el operador >>= y concéntrese en el let . También tenga en cuenta que la sangría ya no importa.

main = readFile "p8.log" >>= (/t -> let digits = map digitToInt $ concat $ lines t in print (problem_8 digits))


Primero, ¿por qué abrazos? La plataforma Haskell es generalmente el camino recomendado para los novatos, que viene con GHC.

Ahora, let a la palabra clave let . La forma más simple de esta palabra clave está destinada a ser siempre utilizada con.

let {assignments} in {expression}

Por ejemplo,

let two = 2; three = 3 in two * three

Las {assignments} solo están en el alcance en la {expression} correspondiente. Se aplican reglas de diseño regulares, lo que significa que debe estar sangrado al menos tanto como el let que corresponda, y cualquier subexpresión que pertenezca a la expresión let también debe sangrarse al menos tanto. Esto no es 100% cierto, pero es una buena regla general; Las reglas de diseño de Haskell son algo a lo que se acostumbrará con el tiempo a medida que lee y escribe el código Haskell. Solo tenga en cuenta que la cantidad de sangría es la forma principal de indicar qué código pertenece a qué expresión.

Haskell proporciona dos casos de conveniencia en los que no tiene que escribir: hacer notación y enumerar comprensiones (en realidad, comprensión de mónadas). El alcance de las asignaciones para estos casos prácticos está predefinido.

do foo let {assignments} bar baz

Para la notación do , las {assignments} están en el alcance de cualquier declaración que siga, en este caso, bar y baz , pero no foo . Es como si hubiéramos escrito

do foo let {assignments} in do bar baz

Enumere las comprensiones (o realmente, cualquier comprensión de mónadas) desugar en la notación do, para que proporcionen una facilidad similar.

[ baz | foo, let {assignments}, bar ]

Las {assignments} están en el alcance de las expresiones bar y baz , pero no para foo .

where es algo diferente. Si no me equivoco, el alcance de where alinea con una definición de función particular. Asi que

someFunc x y | guard1 = blah1 | guard2 = blah2 where {assignments}

las {assignments} en esta cláusula where tienen acceso a x y y . guard1 , guard2 , blah1 y blah2 tienen acceso a {assignments} de esta cláusula where . Como se menciona en el tutorial que ha vinculado, esto puede ser útil si varios guardias reutilizan las mismas expresiones.


Respuesta corta : use let sin in en el cuerpo de un do-block, y en la parte después de | en una lista de comprensión. En cualquier otro lugar, use let ... in ...

La palabra clave let se usa de tres maneras en Haskell.

  1. La primera forma es una expresión let .

    let variable = expression in expression

    Esto se puede usar siempre que se permita una expresión, por ejemplo

    > (let x = 2 in x*2) + 3 7

  2. El segundo es una declaración de let . Esta forma solo se usa dentro de la notación do, y no se usa in

    do statements let variable = expression statements

  3. El tercero es similar al número 2 y se usa dentro de la lista de comprensiones. Nuevamente, no in .

    > [(x, y) | x <- [1..3], let y = 2*x] [(1,2),(2,4),(3,6)]

    Esta forma vincula una variable que está en el alcance en generadores posteriores y en la expresión anterior a | .

La razón de su confusión aquí es que las expresiones (del tipo correcto) se pueden usar como declaraciones dentro de un do-block, y let .. in .. sea ​​solo una expresión.

Debido a las reglas de indentación de haskell, una línea indentada más allá de la anterior significa que es una continuación de la línea anterior, por lo que este

do let x = 42 in foo

se analiza como

do (let x = 42 in foo)

Sin sangría, obtienes un error de análisis:

do (let x = 42 in) foo

En conclusión, nunca lo use in una lista de comprensión o un do-block. Es innecesario y confuso, ya que esos constructos ya tienen su propia forma de let .