I'm trying to nest a couple let statements, but I'm getting syntax errors that don't make sense to me. I'm really new to Haskell programming so I'm sure it's something I just don't understand (probably having to do with the spacing). I understand that let and in must be in the same column.
Why is it that:
aaa = let y = 1+2
z = 4+6
in y+z
Works perfectly fine, whereas
aaa = let y = 1+2
z = 4+6
in let f = 3
e = 3
in e+f
gives me the error: "Syntax error in expression (unexpected `=')"
In the second example, the z = ... isn't aligned with the y = .... In a let block, every definition has to be aligned.
I suspect you're indenting with tab characters, and have your editor set to display tabs as less than 8 spaces, making it look like it's aligned to you. You should replace the tab with spaces, and preferably set your editor to expand tabs into spaces to avoid problems like this in the future.
Related
I often read that I shouldn't mix tabs and spaces in Haskell, or that I shouldn't use tabs at all. Why?
The problem is twofold. First of all, Haskell is indentation sensitive, e.g. the following code isn't valid:
example = (a, b)
where
a = "Hello"
b = "World"
Both bindings need to be indented with the same number of spaces/tabs (see off-side rule). While it's obvious in this case, it's rather hidden in the following one, where I denote a space by · and a tab by »:
example = (a, b)
··where
····a = "Hello"
» b = "World"
This will look like valid Haskell code if the editor will show tabs aligned to multiples by four. But it isn't. Haskell tabs are aligned by multiples of eight, so the code will be interpreted like this:
example = (a, b)
··where
····a = "Hello"
» b = "World"
Second, if you use only tabs, you can end up with a layout that doesn't look right. For example, the following code looks correct if a tab gets displayed with six or more spaces (eight in this case):
example = (a, b)
» where» a = "Hello"
» » b = "World"
But in another editor that uses 4 spaces it won't look right anymore:
example = (a, b)
» where» a = "Hello"
» » b = "World"
It's still correct, though. However, someone who's used to spaces might reindent b' binding with spaces and end up with a parser error.
If you enforce a code convention throughout your code that makes sure that you only use tabs at the beginning of a line and use a newline after where, let or do you can avoid some of the problems (see 11). However, current releases of GHC warn about tabs by default, because they have been a source of many parser errors in the past, so you probably want to get rid of them too.
See also
A reddit thread on the topic (majority pro spaces, but some pro tabs)
Good Haskell Style (pro spaces)
Yet Another Tabs v Space debate (pro mixing)
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 am doing some haskell exercises to learn the language and I have a syntax error I was hoping someone could help me with:
-- Split a list l at element k into a tuple: The first part up to and including k, the second part after k
-- For example "splitAtIndex 3 [1,1,1,2,2,2]" returns ([1,1,1],[2,2,2])
splitAtIndex k l = ([l !! x | x <- firstHalfIndexes], [l !! x | x <- firstHalfIndexes])
where firstHalfIndexes = [0..k-1]
secondHalfIndexes = [k..(length l-1)]
The syntax error is "parse error on input ‘=’" and seems to be coming from my second where clause, but I can't work out why the first where clause is ok but not the second?
The Haskell Report specifies that tab characters flesh out text to the next multiple of eight. Your code appears to assume that it gets fleshed out to the next multiple of four. (My best guess. Might also be configured to be five or six, but those settings seem less popular than four.)
See my page on tabs for ideas on how to safely use tabs in Haskell code; or else do what most other folks do and configure your editor to expand tabs to spaces.
For an example of the style I use, your current code looks like this to the compiler (using > to mark tabs and _ for spaces):
splitAtIndex_..._=_...
> where_> firstHalfIndexes_=_...
> > > secondHalfIndexes_=_...
I would write it to look like this to the compiler:
splitAtIndex_..._=_...
> where_> firstHalfIndexes_=_...
> ______> secondHalfIndexes_=_...
This also looks correct with four-space tabstops (and indeed any size tabstop):
splitAtIndex_..._=_...
> where_> firstHalfIndexes_=_...
> ______> secondHalfIndexes_=_...
(Actually, I would probably just use one space after where rather than a space and a tab, but that's an aesthetics thing, not really a technical one.)
I'm running GHC version 7.8.3 on Windows 7.
Ok, this is not about fancy code snippets. I'm just trying not be a noob here and actually compile something in a way that vaguely resembles the structure of side-effect languages.
I have the following code:
main =
do {
let x = [0..10];
print x
}
I've learned here, that the keyword do is a fancy syntactic sugar for fancy monadic expressions. When I try to compile it, I get the following error:
main.hs:4:1: parse error on input 'print'
And I've learned in this other question, that tabs in Haskell are evil, so I've tried to omit them:
main =
do {
let x = [0..10];
print x
}
And I've failed miserably, because the parse error persists.
I've also learned here, that print is a syntactic sugar for the fancy equivalent:
main =
do {
let x = [0..10];
putStrLn $ show x
}
But then I get this error instead:
main.hs:4:9: parse error on input 'putStrLn'
Trying to face my despair, I've tried to omit the let keyword, after reading this answer:
main =
do {
x = [0..10];
print x
}
And then I get:
main.hs:4:1: parse error on input '='
And in a final useless attempt, I've even tried to omit the ';' like this:
main =
do {
let x = [0..10]
print x
}
And got:
main.hs:4:1: parse error on input 'print'
So,
How to properly use monadic expressions in Haskell without getting parse errors? Is there any hope?
It took me a while to see what was actually going on here:
main =
do {
let x = [0..10];
print x
}
The above looks as if we have a do with two statements, which is perfectly fine. Sure, it is not common practice to use explicit braces-and-semicolons when indentation implicitly inserts them. But they shouldn't hurt... why then the above fails parsing?
The real issue is that let opens a new block! The let block has no braces, so the indentation rule applies. The block starts with the definition x = [0..10]. Then a semicolon is found, which promises that another definition is following e.g.
let x = [0..10] ; y = ...
or even
let x = [0..10] ;
y = ... -- must be indented as the x above, or more indented
However, after the semicolon we find print, which is even indented less than x. According to the indentation rule, this is equivalent to inserting braces like:
main =
do {
let { x = [0..10]; }
print x
}
but the above does not parse. The error message does not refer to the implicitly inserted braces (which would be very confusing!), but only to the next line (nearly as confusing in this case, unfortunately).
The code can be fixed by e.g. providing explicit braces for let:
main = do { let { x = [0..10] };
print x }
Above, indentation is completely irrelevant: you can add line breaks and/or spaces without affecting the parsing (e.g. as in Java, C, etc.). Alternatively, we can move the semicolon below:
main = do { let x = [0..10]
; print x }
The above semicolon is on the next line and is less indented than x, implicitly inserting a } which closes the let block. Here indentation matters, since let uses the indentation rule. If we indent the semicolon more, we can cause the same parse error we found earlier.
Of course, the most idiomatic choice is using the indentation rule for the whole code:
main = do let x = [0..10]
print x
I was about to say, with no useful information, that
main = do
let x = [0..10]
print x
Was working for me, but I'm now off to read about the in within the braces.
As a slight aside, I found http://echo.rsmw.net/n00bfaq.html quite handy for reading about identation/formatting.
main = do let x = [0..10]
print x
works for me
and so does
main = do { let x = [0..10]
in print x }
I think you're trying to mix some different syntax options up.
Search for "vim haskell indent" on SO. There are lot of answers for how to configure Vim for Haskell indentation. None of them really "work". They don't provide code as is recommended by the Haskell indentation wiki page. For example, alignment of statements in a do or let block, the = and | of a data type, etc.
Does a Vim solution exist that generates code like the wiki?
This might not be the answer your are looking for, but there is a way you can follow the indentation wiki guide and be compatible with most editors.
For example, do-blocks
Instead of
myFunc x = do y <- bar
return $ x + y
You can indent it like this
myFunx x = do
y <- bar
return $ x + y
This is explicitly mentioned as an acceptable alternative in the indentation wiki.
In the same way, you can format data types
data FooBar
= Foo
| Bar
| Asdf
Guards
myFunc x
| x < 0 = 0
| otherwise = x
Where-clauses
myFunc x = x + y + c where
y = x + 5
c = x * y
And so on...
I personally started to use this kind of style because, like you said, no editor could reliable indent the code otherwise. This works better in all editors, as the indentation is always a multiple of four (or whatever else you pick for your base indentation level). As I used this style, I also started to prefer this consistent indentation level visually, so I wouldn't go back at this point even if editors got smarter.