1

I want to create my own list data structure called Nodes. Then I will use my ListConverter class, which contains the 'toList' function, and create an instance of it.

data Nodes a = Empty
             | Node a (Nodes a)

class ListConverter a where
    toList :: a -> [Integer]

instance (Integral a) => ListConverter (Nodes a) where
    toList Empty = []
    toList (Node x Empty) = [x]
    toList (Node x y) = x : toList y

GHCi tells me, that the expected type is 'Integer' but is currently 'a'. Im very confused, because in the instance I give a type for a (Integral). Here's the error message:

error:
    * Couldn't match expected type `Integer' with actual type `a'
      `a' is a rigid type variable bound by
        the instance declaration
        at main.hs:7:10-48
    * In the expression: x
      In the expression: [x]
      In an equation for `toList': toList (Node x Empty) = [x]
    * Relevant bindings include
        x :: a (bound at main.hs:9:18)
        toList :: Nodes a -> [Integer] (bound at main.hs:8:5)
  |
9 |     toList (Node x Empty) = [x]
  |                              ^
2
  • 2
    x is bounded to Integrals but not all Integrals are Integers. I think that's the problem. Commented May 29, 2019 at 23:30
  • You said that you want to use ListConverter to "create an instance of it", where by "it" I believe you mean your Nodes type. If this means that you expect toList to give you a value of type Nodes a (for some a) then you will be disappointed, because it would take a value of type Nodes a and give a [Integer]. Commented May 29, 2019 at 23:52

2 Answers 2

3

Your instance of ListConverter is expected to accept any value of class Integral for "a", but Integer is a specific type, not a class; you'd have to do this:

instance ListConverter (Nodes Integer) where

That or, conversely, make your ListConverter class capable of producing a list of whatever type your Nodes value contains:

class ListConverter f where
    toList :: f a -> [a]

instance ListConverter Nodes where
    toList Empty = []
    toList (Node x y) = x : toList y

(The second equation for toList - (Node x Empty) - is unnecessary)

Sign up to request clarification or add additional context in comments.

Comments

1

The problem with this instance is very simply stated. You have given the signature:

toList :: a -> [Integer]

But your attempted instance actually has type Nodes a -> [a]. This doesn't work unless a is the Integer type - yet you've claimed it works for all Integral a. This includes other types such as Int.

One solution is just to restrict your instance:

instance ListConverter (Nodes Integer) where...

This will work - but doesn't in my opinion really respect the spirit of what you probably intended the class for.

The best solution I think is to recognise that both lists and your Nodes type are paramaterised by another type, and define the class in such a way as to do the conversion over a common base class. That sounds more complicated than it is, I just mean:

class ListConverter l where
    toList :: l a -> [a]

Then you can write an instance ListConverter Nodes where..., and just copy your existing toList definition. (Whose middle line, I will point out in passing, is redundant.)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.