i am new to haskell and i am trying to make the following code work:
abc :: fooType
abc = do
let loop c d = do
let q = borrow "a"
d2 = d + q
c2 = c + 1
if c2 == 10
then
if d2 >= 60
then
maybeB <- cast "b"
return $ isJust maybeB
else
return $ False
else
loop c2 d2
loop 0 0
i keep getting:
error: parse error on input `let'
let q = borrow "a"
the code looks correct to me, would that be a problem with indentation? I know do blocks have some specific rules on how to set up indentation but from what i've been reading it looks correct.., can anyone spot what the problem is?
ps: borrow returns Int > 0,
cast returns maybe int. But the compilation is failing on line2
let and do are both block heralds -- that means that the start of the next lexical token starts a block and sets the indentation level of that block. Additionally, indentation must increase to nest blocks. So:
abc = do -- block herald
-- "let" is the next token after a block herald, so it sets an indentation level;
-- it is also itself a block herald
-- "loop" is the next token after a block herald, so it sets an indentation level
-- "do" is a block herald
let loop = do
-- "let" is the next token after a block herald, so it sets an indentation level,
-- **and must be deeper than the enclosing indentation;**
-- it is also a block herald
-- "q" is the next token after a block herald, so it sets an indentation level
let q = ...
-- "d2" must use the indentation level of the block it wants to be in;
-- presumably the enclosing "let"
d2 = ...
c2 = ...
-- this "if" must use the indentation of the block it wants to be in;
-- presumably the closest enclosing "do" block
if ...
-- this "then" can be indented the same as the "if" above it, but I find
-- that confusing; my preferred style indicates the nesting structure
then ...
else ...
-- this "loop" must use the indentation of the block it wants to be in; presumably the outermost "do" block
loop
There's a lot going on in the second line, so it's easy to lose track of all the things you need to think about. Anyway, the main mistake in your code is that loop sets an indentation level, and the let shortly after it must be indented more than it.
Related
module HW2sol
where import HW2types
ins :: Eq a => a -> Bag a -> Bag a
ins x [] = [(x,1)]
ins x (y:ys) =
if x == fst y
then (x, snd y + 1) : ys
else y : (ins x ys)
HMW2types in this code is just a file that contains all of the declarations for the bag type. I have even copied and pasted other functions from online and they get the same error. This function takes an element and adds it to a bag.
[2 of 2] Compiling HW2sol ( HMW2sol.hs, HMW2sol.o )
HMW2sol.hs:5:1: parse error on input `ins'
You may be aware of Haskell's indentation rules. Anywhere you have a block of declarations (as in a let <decls> in <expr>, or a where, etc) or a block of statements (as in a do block), or a block of patterns & branches (as in a case expression) Haskell identifies the start of each entry in the block by the following logic:
Identify the column of the first character of the first entry in the block. Call this column C.
The next line that is indented less than C indicates the end of the block (and is not part of the block).
Before the end of the block, any line that is indented exactly C characters starts a new entry in the block.
Before the end of the block, any line that is indented more than C is a continuation line of the previous entry
This logic is consistently applied to all of Haskell's "block" constructs. They all have to be aligned this way1. And it turns out that the top-level declarations in a module form an aligned block! We just don't usually bother to think of them that way because they are conventionally started at column 1 (which means it isn't possible to end the block as no line can start before the first column; people normally just put all their top-level declarations at the start of the line and indent any continuations without ever thinking about "aligning the module's main block").
However, your code does not (successfully) use this conventional layout. Because you didn't insert a linebreak after the where, the first declaration begins at column 7, not column 1!
where import HW2types
^
1234567
Your type declaration of ins begins on column 1, so by rule 2 above (1 is less than 7) this indicates the end of the module's block of definitions; the compiler has to parse ins :: Eq a => ... as something that can follow the main block in the module, instead of parsing it as a declaration in the main block. That's why you get a parse error (nothing can follow the main block).
If you start your module's main block at column 7 then all of your declarations have to be indented to column 7. This actually works:
module HW2sol
where import HW2types
ins :: Eq a => a -> Bag a -> Bag a
ins x [] = [(x,1)]
ins x (y:ys) =
if x == fst y
then (x, snd y + 1) : ys
else y : (ins x ys)
However you'll probably find it much easier to simply put a line break after the where and have import HW2types on a new line.
1 Alternatively, blocks and their entries can be explicitly delimited with braces and semicolons. But this is not usual style in Haskell.
Let's say I have this piece of code:
data Command = Forward Integer
| Backwards Integer
doSomething givenCommand
| Forward value <- givenCommand = undefined
where calculatedValue = sqrt value
Let's say the undefined line, which would use the calculatedValue, is going to be really long and the calculatedValue calculation also much longer, so to make the code more readable, I'd like to use a where clause.
The problem is that the variable value, specified in the guard pattern match, is not in scope for the where clause.
Is there a way around this, which wouldn't force me to perform the calculation on the guard line ?
Thanks.
value is indeed not in the scope of where since it is not said that the given pattern guard will "fire". If the pattern fails, then there is no value, so that makes not much sense.
You can use a let … in … clause here:
doSomething givenCommand
| Forward value <- givenCommand = let calculatedValue = sqrt value in undefined
| … = …
you here however do not need a pattern guard, you can pattern match in the head of the doSomething function:
doSomething (Forward value) = undefined
where calculatedValue = sqrt value
doSomething (…) = …
I have a list of Strings, errors. I do some checks and if any fail, I append a message to errors. Something like this:
let errors = []
let errors' = errors ++ if (check1 fails) then ["check1 failed"] else []
let errors'' = errors' ++ if (check2 fails) then ["check2 failed"] else []
Surely there is a more idiomatic way to accumulate changes to errors without making a new variable every time. Do I need to break out Data.IORef for mutable variables? Seems like overkill.
If I simply remove the apostrophes, the compiler returns an error because it gets caught in an infinite loop.
You could group the conditions and messages together
checksTodo = [(check1 fails, "check1 failed"), (check2 fails, "check2 failed")]
errors = map snd (filter fst checksTodo)
If you are comfortable using the list comprehension syntax, you could instead write it in a more readable fashion:
errors = [ msg | (cond, msg) <- checksTodo, cond ]
If I simply remove the apostrophes, the compiler returns an error because it gets caught in an infinite loop.
This is happening because let bindings in Haskell (unlike most languages) are recursive by default. Which means that if you say
let errors = errors ++ if (check1 fails) then ["check1 failed"] else []
the compiler will treat it as a recursive definition. When you try to evaluate errors at runtime, you go into an infinite loop as you need errors to compute errors.
Another alternative:
let errors =
[ "check1 failed" | check1 fails ] ++
[ "check2 failed" | check2 fails ] ++
...
What theindigamer said, plus, the idiomatic way to do error checking is usually having your checker return an Either: if something goes wrong, produce a Left with the error message, otherwise a Right with the result.
Since, in this case, your checks aren't producing an actual result, you can make the result the unit type (); thus, you can convert your checks to generate Either like this:
check1Either = if check1 fails then Left "check1 failed" else Right ()
And then, just run the checks and filter the elements with a Left using the lefts function in Data.Either:
import Data.Either
errors = lefts [check1Either, check2Either]
(You might ask, if there isn't going to be a result to fill Right with, why not use Maybe? You can, and filter errors with catMaybes from Data.Maybe; it's just that Nothing is usually interpreted to mean that the computation failed, and Just usually means success - the opposite of what happens here - whereas, idiomatically speaking Left is usually interpreted as an error)
Why doesn't line 5 contain an indentation error. I expected to get a parse error on compilation. I expected that the + on line 5 would have to be aligned under the * in line 4.
module Learn where
x = 10
* 5
+ y -- why isn't this incorrect indentation
myResult = x * 5
y = 10
It compiles because there's no block there to consider.
Indentation only matters after where, let, do, case of.
These keywords start a block of things, and it is important to understand whether a line continues the previous entry, starts a new entry, or ends the block.
case f 5 of
A -> foo
32 -- continues the previous entry
B -> 12 -- starts a new entry
+ bar 43 -- ends the case
After = we do not need to split a block into entries: there's only a single expression. Hence no indentation rules apply.
This compiles because the definition of x was all to the right of the beginning of x. It's not important where each line starts as long as those lines are indented to the right of x.
I'm currently working my way through Learn You a Haskell for Great Good, and I'm trying to modify one of the code snippets in chapter nine, "Input and Output" to handle errors correctly:
main = do
(command:args) <- getArgs
let result = lookup command dispatch
if result == Nothing
then
errorExit
else
let (Just action) = result
action args
where
dispatch :: [(String, [String] -> IO ())]
is an association list
and
errorExit :: IO ()
is some function that prints an error message.
Compiling this with GHC gives the error message
todo.hs:20:13: parse error in let binding: missing required 'in'
which (to my understanding), seems to be saying that the "let" here doesn't realise it's in a "do" block.
Adding "do" on lines five and seven (after "then" and "else" respectively), changes the error message to
todo.hs:20:13:
The last statement in a 'do' block must be an expression
let (Just action) = result
todo.hs:21:5: Not in scope: `action'.
and now, whilst I agree with the first error message, I also have that one of my variables has jumped out of scope? I've double checked my alignment, and nothing seems to be out of place.
What is the appropriate way to assign a varaible within an if clause that is within a do block?
My suggestion is to not use if in the first place, use case. By using case you get to test the value and bind the result to a variable all in one go. Like this:
main = do
(command:args) <- getArgs
case lookup command dispatch of
Nothing -> errorExit
Just action -> action args
For a more in-depth discussion on why we should prefer case over if see boolean blindness.
#svenningsson suggested the right fix. The reason your original fails is because let clauses can only appear at the top level of a do block - they're simple syntactic sugar that doesn't look into inner expressions:
do let x = 1
y
desugars to the let expression
let x = 1 in y
Alas, in a do block, an expression clause like if ... then ... else ... has no way to declare variables in the rest of the do block at all.
There are at least two possible ways to get around this.
Absorb the remainder of the do block into the expression:
main = do
(command:args) <- getArgs
let result = lookup command dispatch
if result == Nothing
then
errorExit
else do
let (Just action) = result
action args
(This is essentially the method #svenningsson uses in his better case version too.)
This can however get a bit awkward if the remainder of the do expression needs to be duplicated into more than one branch.
("Secret" trick: GHC (unlike standard Haskell) doesn't actually require a final, inner do block to be indented more than the outer one, which can help if the amount of indentation starts getting annoying.)
Pull the variable declaration outside the expression:
main = do
(command:args) <- getArgs
let result = lookup command dispatch
action <- if result == Nothing
then
errorExit
else do
let (Just action') = result
return action'
action args
Here that requires making up a new variable name, since the pattern in the let clause isn't just a simple variable.
Finally, action was always out of scope in the last line of your code, but GHC works in several stages, and if it aborts in the parsing stage, it won't check for scope errors. (For some reason it does the The last statement in a 'do' block must be an expression check at a later stage than parsing.)
Addendum: After I understood what #Sibi meant, I see that result == Nothing isn't going to work, so you cannot use if ... then ... else ... with that even with the above workarounds.
You are getting an error because you are trying to compare values of function type. When you perform the check if result == Nothing, it tries to check the equality of Nothing with the value of result which is a type of Maybe ([String] -> IO ()).
So, if you want it to properly typecheck, you have to define Eq instances for -> and that wouldn't make any sense as you are trying to compare two functions for equality.
You can also use fmap to write your code:
main = do
(command:args) <- getArgs
let result = lookup command dispatch
print $ fmap (const args) result