Reputation: 103
This works in the ghci
data MyList a = Empty | Cons a (MyList a) deriving (Show, Eq, Read, Ord)
let x = Cons(21, Cons(12, Empty))
However when I type:
Prelude> x
I get this error:
No instance for (Show (MyList (Integer, MyList (Integer, MyList a0) ->
MyList (Integer, MyList a0)) ->
MyList (Integer, MyList (Integer, MyList a0) ->
MyList (Integer, MyList a0)))) arising from a use of `print'
Upvotes: 1
Views: 523
Reputation: 103
You are using the wrong syntax for function application. The following code does what you want:
let x = Cons 21 (Cons 12 Empty)
The reason for this is that the Cons
constructor is a curried function, but you are treating it as an uncurried function.
Consider the following function adding two integers:
add :: Int -> (Int -> Int)
add = \x -> (\y -> x + y)
Here we say add
is a function, which takes an argument x
of type Int
and returns a function,
which takes an argument y
of type Int
and returns x + y
of type Int
.
We can apply this function for example as (add 1) 2
evaluating to 3
.
Function application is left-associative in Haskell, which means that we don't need the parentheses
in (add 1) 2
and can simply write add 1 2
.
The function type constructor ->
is right-associative in Haskell, which means that we don't need the parentheses in add :: Int -> (Int -> Int)
and can simply write add :: Int -> Int -> Int
.
Also we don't have to explicitly define add
using lambdas and can use the following notation:
add :: Int -> Int -> Int
add x y = x + y
Encoding multi-parameter functions as single-parameter functions returning single-parameter functions is quite common in Haskell. This approach has the nice property, that we can also partially apply a function. For example the following function takes a single Int
and adds 2:
add2 :: Int -> Int
add2 x = add 2 x
But we can also partially apply add
and simply write:
add2 :: Int -> Int
add2 = add 2
This is also called point-free notation, where parameters are referred to as points.
An alternative encoding of multi-parameter functions can be done using tuple-values, i.e.
add' :: (Int, Int) -> Int
add' (x, y) = x + y
We can invoke this function for example as add' (2, 3)
, which constructs the pair (2, 3) :: (Int, Int)
and passes it as a single argument to the add'
function.
In the standard library are two functions to convert functions between the two styles.
curry :: ((a, b) -> c) -> a -> b -> c
curry f x y = f (x, y)
uncurry :: (a -> b -> c) -> (a, b) -> c
uncurry f (x, y) = f x y
For example curry add'
gives us add
, and uncurry add
gives us add'
.
Note that we could also write the uncurried application as add'(2, 3)
, which together with partial application and polymorphism explains why let x = Cons(21, Cons(12, Empty))
doesn't directly lead to an error, but ghci subsequently says misterious things about the evaluation of x
.
What happens here is that (12, Empty)
is pair of type (Int, MyList a)
for some type a
.
This pair is then used as the first argument in Cons (12, Empty)
, so we get a partially applied function which takes
a MyList (Int, MyList a)
and appends (12, Empty)
as an element to this list.
The same happens for Cons(21, Cons(12, Empty))
where we partially apply a pair of 21 and the before mentioned partial function. In the end we tell ghci to print a function, which it cannot display and hence complains about a missing Show
instance for the corresponding function type.
Upvotes: 8