# I'm really confused about function declarations in Haskell

This question already has several other perfectly good answers explaining how to solve your problem. I don’t want to do that; instead, I will go through each line of your code, progressively correct the problems, and hopefully help you understand Haskell a bit better.

First, I’ll copy your code for convenience:

```
allEqual :: Eq a => a -> a -> a -> Bool
allEqual x y z do
Bool check <- x == y
Bool nextC <- y == z
if check == nextC
then True
else False
```

The first line is the type signature; this is already explained well in other answers, so I’ll skip this and go on to the next line.

The second line is where you are defining your function. The first thing you’ve missed is that you need an equals sign to define a function: function definition syntax is `functionName arg1 arg2 arg3 … = functionBody`

, and you can’t remove the `=`

. So let’s correct that:

```
allEqual :: Eq a => a -> a -> a -> Bool
allEqual x y z = do
Bool check <- x == y
Bool nextC <- y == z
if check == nextC
then True
else False
```

The next error is using `do`

notation. `do`

notation is notorious for confusing beginners, so don’t feel bad about misusing it. In Haskell, `do`

notation is only used in specific situations where it is necessary to execute a sequence of statements line by line, and especially when you have some side-effect (like, say, printing to the console) which is executed with each line. Clearly, this doesn’t fit here — all you’re doing is comparing some values and returning a result, which is hardly something which requires line-by-line execution. So let’s get rid of that `do`

:

```
allEqual :: Eq a => a -> a -> a -> Bool
allEqual x y z =
let Bool check = x == y
Bool nextC = y == z
in
if check == nextC
then True
else False
```

(I’ve also replaced the `<-`

binding with `let … in …`

, since `<-`

can only be used within a `do`

block.)

Next, another problem: `Bool check`

is not valid Haskell! You may be familiar with this syntax from other languages, but in Haskell, a type is always specified using `::`

, and often with a type signature. So I’ll remove `Bool`

before the names and add type signatures instead:

```
allEqual :: Eq a => a -> a -> a -> Bool
allEqual x y z =
let check :: Bool
check = x == y
nextC :: Bool
nextC = y == z
in
if check == nextC
then True
else False
```

Now, at this point, your program is perfectly valid Haskell — you’ll be able to compile it, and it will work. But there’s still a few improvements you can make.

For a start, you don’t need to include types — Haskell has type inference, and in most cases it’s fine to leave types out (although it’s traditional to include them for functions). So let’s get rid of the types in the `let`

:

```
allEqual :: Eq a => a -> a -> a -> Bool
allEqual x y z =
let check = x == y
nextC = y == z
in
if check == nextC
then True
else False
```

Now, `check`

and `nextC`

are only used in one place — giving them names doesn’t do anything, and only serves to make the code less readable. So I’ll inline the definitions of `check`

and `nextC`

into their usages:

```
allEqual :: Eq a => a -> a -> a -> Bool
allEqual x y z =
if (x == y) == (y == z)
then True
else False
```

Finally, I see you have an expression of the form `if <condition> then True else False`

. This is redundant — you can simply return the `<condition>`

with the same meaning. So let’s do that:

```
allEqual :: Eq a => a -> a -> a -> Bool
allEqual x y z = (x == y) == (y == z)
```

This is much, much better than the code you started with!

(There is actually one more improvement that you can make to this code. At this point, it should be obvious that your code has a bug. Can you find it? And if so, can you fix it? Hint: you can use the `&&`

operator to ‘and’ two booleans together.)

Lets start with a function that takes a single `Int`

:

```
allEqual1Int :: Int -> Bool
allEqual1Int x = True
allEqual1Int' :: Int -> Bool
allEqual1Int' x =
if x == x
then True
else False
```

If we compare that to your line

```
allEqual x y z do
```

we notice that you miss a `=`

and that you don't need a `do`

.

A version for `String`

could look like

```
allEqual1String' :: String -> Bool
allEqual1String' x =
if x == x
then True
else False
```

and we observe that *the same implementation* works for multiple types (`Int`

and `String`

) provided they support `==`

.

Now `a`

is a type variable, think of it as a variable such that its value is a type. And the requirement that the given type supports `==`

is encoded in the `Eq a`

constraint (Think of it as an interface). Therefore

```
allEqual :: Eq a => a -> a -> a -> Bool
```

works for *any* such type that supports `==`

.

Haskell is a bit strange language for those who programmed in different languages before. Let's first have a look at this function:

```
allEqual :: Int -> Int -> Int -> Bool
```

You can look at this like that: the last "thing" after "`->`

" is a return type. Previews "things" are parameters. From that, we know the function accepts three parameters that are `Int`

and returns the `Bool`

.

Now have a look at your function.

```
allEqual :: Eq a => a -> a -> a -> Bool
```

There is an extra syntax "`Eq a =>`

". What it basically does is all the following "`a`

" in declaration must implement `Eq`

. So it is a more generalized version of the first function. It accepts three parameters that implement "`Eq`

" and returns `Bool`

. What the function should probably do is check if all values are equal.

Now let's have a look at your implementation. You are using a do syntax. I feel like it is not the best approach in the beginning. Let's implement a very similar function which checks if all parameters are equal to 3.

```
allEq3 :: Int -> Int -> Int -> Bool
allEq3 x y z = isEq3 x && isEq3 y && isEq3 z
where
isEq3 :: Int -> Bool
isEq3 x = x == 3
```

Like in your example, we have three parameters, and we return `Bool`

. In the first line, we call function `isEq3`

on all the parameters. If all these calls return true `allEq3`

will also return true. Otherwise, the function will return false. Notice that the function `isEq3`

is defined below after the keyword "where". This is a very common thing in Haskell.

So what we did here is taking a big problem of checking if all the parameters are equal to 3 and divide it into smaller pieces which check whether a value is equal to 3.

You can improve this implementation a lot but I think this is the best way to take the first steps in Haskell. If you really want to learn this language you should have a look at this.