In the following code, the last phrase I can put an in
in front. Will it change anything?
Another question: If I decide to put in
in front of the last phrase, do I need to indent it?
I tried without indenting and hugs complains
Last generator in do {...} must be an expression
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
Ok, so people don't seem to understand what I'm saying. Let me rephrase: are the following two the same, given the context above?
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
Another question concerning the scope of bindings declared in let
: I read here that:
where
Clauses.
Sometimes it is convenient to scope bindings over several guarded equations, which requires a where clause:
f x y | y>z = ... | y==z = ... | y<z = ... where z = x*x
Note that this cannot be done with a let expression, which only scopes over the expression which it encloses.
My question: so, the variable digits shouldn't be visible to the last print phrase. Do I miss something here?
In Haskell let, binding is used to bind the variables, which are very local. In Haskell, we can define any type of variable using let keyword before the variable name in Haskell. But their scope is local, we also have let in Haskell which is another form of defining the variable and use them after it.
It is important to know that let ... in ... is an expression, that is, it can be written wherever expressions are allowed. In contrast, where is bound to a surrounding syntactic construct, like the pattern matching line of a function definition.
in goes along with let to name one or more local expressions in a pure function.
Haskell guards are used to test the properties of an expression; it might look like an if-else statement from a beginner's view, but they function very differently. Haskell guards can be simpler and easier to read than pattern matching .
Short answer: Use let
without in
in the body of a do-block, and in the part after the |
in a list comprehension. Anywhere else, use let ... in ...
.
The keyword let
is used in three ways in Haskell.
The first form is a let-expression.
let variable = expression in expression
This can be used wherever an expression is allowed, e.g.
> (let x = 2 in x*2) + 3 7
The second is a let-statement. This form is only used inside of do-notation, and does not use in
.
do statements let variable = expression statements
The third is similar to number 2 and is used inside of list comprehensions. Again, no in
.
> [(x, y) | x <- [1..3], let y = 2*x] [(1,2),(2,4),(3,6)]
This form binds a variable which is in scope in subsequent generators and in the expression before the |
.
The reason for your confusion here is that expressions (of the correct type) can be used as statements within a do-block, and let .. in ..
is just an expression.
Because of the indentation rules of haskell, a line indented further than the previous one means it's a continuation of the previous line, so this
do let x = 42 in foo
gets parsed as
do (let x = 42 in foo)
Without indentation, you get a parse error:
do (let x = 42 in) foo
In conclusion, never use in
in a list comprehension or a do-block. It is unneccesary and confusing, as those constructs already have their own form of let
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With