People going from zero to Haskell are likely gain a misunderstanding or miss a point that isn't stressed enough. Here are some mistakes that have been observed from multiple sources.

+

People going from zero to Haskell are likely to gain a misunderstanding or miss a point that isn't stressed enough. Here are some mistakes that have been observed from multiple sources.

== Indentation ==

== Indentation ==

Line 24:

Line 26:

</code>

</code>

−

The above is valid, though not common, C code. It states that if <code>b</code> is true then <code>x = y</code> otherwise <code>x = z</code>. Notice how this makes no sense without <code>z</code>. Similarly, in Haskell an <hask>if</hask>/<hask>then</hask> makes no sense without an <hask>else</hask>.

+

The above is valid C code, a [http://en.wikipedia.org/wiki/Ternary_operation ternary operation], that's used quite commonly as a shortcut to typing out a full if-then-else block. It states that if <code>b</code> is true then <code>x = y</code> otherwise <code>x = z</code>. Notice how this makes no sense without <code>z</code>. Similarly, in Haskell an <hask>if</hask>/<hask>then</hask> makes no sense without an <hask>else</hask>.

<haskell>

<haskell>

Line 43:

Line 45:

</haskell>

</haskell>

−

Such uses can be more succinct if they use the <hask>when</hask> keyword:

+

Such uses can be more succinct if they use the <hask>when</hask> function (from the Control.Monad module):

<haskell>

<haskell>

main = do

main = do

startNetwork <- askUser "Network? "

startNetwork <- askUser "Network? "

−

when startNetwork (do

+

when startNetwork $ do

iface <- initNetworkInterface

iface <- initNetworkInterface

−

handlePackets iface )

+

handlePackets iface

</haskell>

</haskell>

+

== Binding of Type Signatures ==

+

Due to the typeclass overloading of numbers, lists of numbers are often typed as:

+

+

<haskell>

+

ghci> [1,2,3,4] :: [Float]

+

</haskell>

+

+

This works fine when the list stands alone, but when applying a function take note the function application binds stronger than the type signature. This means the below signature is invalid:

+

+

<haskell>

+

ghci> map floor [1,2,3,4] :: [Float]

+

</haskell>

+

+

and should instead be:

+

<haskell>

+

ghci> map floor ([1,2,3,4] :: [Float])

+

</haskell>

== '''do''' Notation ==

== '''do''' Notation ==

−

If the [[do notation]] page ever exists I'll advice you to check it out. Until then, understand that a missing <hask>do</hask> from the top of a function or code block can result in your compiler giving an error message citing a much later line number. Also, any new blocks (ex: from an <hask>if</hask> or <hask>case</hask>) must have their own <hask>do</hask>, even if the higher level code block already had one.

+

If the [[do notation]] page ever exists I'll advise you to check it out. Until then, understand that a missing <hask>do</hask> from the top of a function or code block can result in your compiler giving an error message citing a much later line number. Also, any new blocks (ex: from an <hask>if</hask> or <hask>case</hask>) must have their own <hask>do</hask>, even if the higher level code block already had one.

Sorry this isn't the full picture - for an inverse point of view see [[do notation considered harmful]].

Sorry this isn't the full picture - for an inverse point of view see [[do notation considered harmful]].

Line 73:

Line 92:

<haskell>

<haskell>

hanoi :: a -> a -> a -> Int -> [(a, a)]

hanoi :: a -> a -> a -> Int -> [(a, a)]

−

hanoi a b c n = hanoi_helper a b c n

+

hanoi source using dest n

−

+

−

hanoi_helper :: a -> a -> a -> Int -> [(a, a)]

+

−

hanoi_helper source using dest n

+

| n == 1 = [(source, dest)]

| n == 1 = [(source, dest)]

−

| otherwise = hanoi_helper source dest using (n-1)

+

| otherwise = hanoi source dest using (n-1)

−

++ hanoi_helper source using dest 1

+

++ hanoi source using dest 1

−

++ hanoi_helper using source dest (n-1)

+

++ hanoi using source dest (n-1)

hanoi_shower :: Show a => [(a, a)] -> String

hanoi_shower :: Show a => [(a, a)] -> String

Line 96:

Line 112:

<hask>

<hask>

Program error: pattern match failure: hanoi_shower

Program error: pattern match failure: hanoi_shower

−

[('a','b'),('a','c')] ++ ([] ++ hanoi_helper 'b' 'a' 'c' (2 - 1))

+

[('a','b'),('a','c')] ++ ([] ++ hanoi 'b' 'a' 'c' (2 - 1))

</hask>

</hask>

Line 110:

Line 126:

Here, <hask>moves</hask> is pattern-matched to type <hask>[(a, a)]</hask> (a list of pairs). The problem is how to iterate over the elements (pairs) of the list while separating the first <hask>a</hask> of each pair from the second <hask>a</hask>.

Here, <hask>moves</hask> is pattern-matched to type <hask>[(a, a)]</hask> (a list of pairs). The problem is how to iterate over the elements (pairs) of the list while separating the first <hask>a</hask> of each pair from the second <hask>a</hask>.

−

The solution above uses list comprehension: the generator <hask>(a, b) <- moves</hask> feeds each pair in turn to the left-hand expression <hask>(a, b)</hask>, and this pair is mapped to the left expression, <hask>"Move " ++ show a ++ " to "++ show b ++ "."</hask>, building a new list of sentences representing moves. Then, the function <hask>unlines</hask> breaks this list into a sequence of lines.

+

The solution above uses list comprehension: The generator <hask>(a, b) <- moves</hask> feeds each pair in turn to the left-hand expression <hask>(a, b)</hask>, and this pair is mapped to the left expression, <hask>"Move " ++ show a ++ " to "++ show b ++ "."</hask>, building a new list of sentences representing moves. Then, the function <hask>unlines</hask> breaks this list into a sequence of lines.

Here is the result of executing the above code in WinHugs:

Here is the result of executing the above code in WinHugs:

Line 157:

Line 173:

There are other ways of iterating over lists as well. One advantage of Haskell is that there are often many ways of performing the same action, including iterating over lists.

There are other ways of iterating over lists as well. One advantage of Haskell is that there are often many ways of performing the same action, including iterating over lists.

+

+

== Guards ==

+

(The following two tips on guards were contributed by the user 7stud in the thread "Top beginner mistakes" (see http://article.gmane.org/gmane.comp.lang.haskell.beginners/1121) on the Haskell-Beginners mailing list on Wed, 4 Mar 2009 21:54:05 +0000 (UTC).)

+

+

Some beginners make the mistake of putting an equals sign after a function name when using guards; ''viz.'':

+

+

<haskell>

+

myfunction x y =

+

| x < 2 = "a"

+

| y > 20 = "b"

+

| otherwise = "c"

+

</haskell>

+

+

This causes a cryptic error message similar to the following to be displayed:

+

+

<hask>

+

dhask.hs:2:4: parse error on input `|'

+

Failed, modules loaded: none.

+

</hask>

+

+

Another common mistake that some beginners make is writing "if" in front of the guard conditions; ''viz.'':

+

+

<haskell>

+

myfunction x y

+

| if x < 2 = "a"

+

| if y > 20 = "b"

+

| otherwise = "c"

+

</haskell>

+

+

This causes a mysterious error message similar to the following to be shown:

+

+

<hask>

+

dhask.hs:2:25: parse error on input `='

+

Failed, modules loaded: none.

+

</hask>

+

+

In both cases, the error messages don't help to identify the problem.

+

+

(Entry added by [[User:DekuDekuplex|Benjamin L. Russell]].)

+

+

== Parentheses ==

+

(The following tip on parentheses was contributed by the user 7stud in the thread "Top beginner mistakes" (see http://article.gmane.org/gmane.comp.lang.haskell.beginners/1121) on the Haskell-Beginners mailing list on Wed, 4 Mar 2009 21:54:05 +0000 (UTC).)

+

+

Some beginners make the mistake of not putting parentheses around arguments of the form x:xs; ''viz.'':

+

+

<haskell>

+

dosomething x:xs = head xs

+

</haskell>

+

+

This causes an ambiguous error message similar to the following to be shown:

Revision as of 21:37, 24 August 2011

Contents

1 Common Mistakes and Incorrect Beliefs By Haskell Beginners

People going from zero to Haskell are likely to gain a misunderstanding or miss a point that isn't stressed enough. Here are some mistakes that have been observed from multiple sources.

1.1 Indentation

Perhaps the first trip-up - you might understand that indentation defines where a code block starts and the lack of an equal amount of indentation indicates the previous code block ended. What some miss is that

then

and

else

must be indented deeper than the

if

statement:

if boolean
then expr1
else expr2

Or they can be on the same line as the if:

if boolean then expr1 else expr2

1.2 If / Then / Else

if-then statements must always include an 'else' portion. It might be best not to think of if-then-else as flow control, as in most imperative languages, but think of it as construction of a value using a well formed expression.

x = b ? y : z;

The above is valid C code, a ternary operation, that's used quite commonly as a shortcut to typing out a full if-then-else block. It states that if b is true then x = y otherwise x = z. Notice how this makes no sense without z. Similarly, in Haskell an

if

/

then

makes no sense without an

else

.

let x =if b then y -- compare to x = b ? y

What is x when b is false? One should also recognize that the types returned by the

then

and

else

branches must match due to Haskells strong and static type system.
When

1.5 Iterating Over a List

Some beginners make the mistake of mistaking a single-element list pattern (such as

[x]

) for a pattern that iterates over every element in the list.
One example that recently (in April, 2008) appeared on the Haskell-Cafe mailing list (see the reply post Re: Embedding newlines into a string?) was the following. Here, one coder attempted to write a function

hanoi

to solve the Towers of Hanoi problem, but to code it so that each tower could be named polymorphically, using, for example, either Chars or Ints. The problematic code segment was the following: