If i'm creating a function, let's take the simplest example:
add x y = x y
if i want to add a Function Type declaration before, for clarity sake
add :: (Int, Int) -> Int
add x y = x y
I get a compile error:
"Couldn't match expected type ‘Int’ with actual type ‘(Int, Int) -> (Int, Int)’".
"The equation(s) for ‘add’ have two arguments, but its type ‘(Int, Int) -> Int’ has only one"
but it compiles flawlessly if i correct it to
add :: (Int, Int) -> Int
add (x, y) = x y
coming from other languages, i actually think it's clearer to use the second form with parenthesis, but in my opinion, both ways should work
1 - what is the reason for not working the first way?
2 - i find the error messages completely confusing so, maybe, the error happens for another reason i don't understand
CodePudding user response:
what is the reason for not working the first way?
In the first expression your type says it takes a 2-tuple as single parameter, and it returns the sum of the two items. But in the "body" of the function, you specify add x y = x y
hence you construct a function that takes a parameter x
that will return a function that will take a parameter y
which maps to x y
.
In Haskell all functions take one parameter. Indeed, your add
function takes one parameter x
. It is short for:
add x = \y -> x y
It thus returns a function that will take a parameter y
and then maps y
to x y
. If you thus construct a function f = add 2
, then f
will take the parameter y
, and map this on 2 y
.
The arrow is a right-associative operator. This means that Int -> Int -> Int
is short for Int -> (Int -> Int)
, it thus is a function that maps an Int
to another function.
You can see the syntax of languages like Java where they call f (x, y)
basically as calling the function f
with one object: a 2-tuple with x
and y
as its two elements.