m0rphism
m0rphism

Reputation: 103

Ghci error: No instance for Show

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

Answers (1)

m0rphism
m0rphism

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.

Curried functions

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.

Uncurried functions

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.

Uncurried <-> Curried

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'.

Back to explaining ghci's rambling

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

Related Questions