4

I'm trying to implement show method of a data type.

data OptionList a b = EmptyOpt | OptionList { optListHead :: a, optListTail :: b } deriving (Read)

instance (Show a, Show b) => Show (OptionList a b) where
    show (OptionList a EmptyOpt) = "{" ++ (show a) ++"}"
    show (OptionList EmptyOpt b) = "{" ++ (show b) ++"}"
    show (OptionList a b) = "{"++ (show a) ++ ", " ++ (show b) ++"}"
    show EmptyOpt = ""

I want the OptionList not to show a comma if one of a or b has a value constructed by EmptyOpt. But the compiler shows the following error:

OptionList.hs:11:28:
    Couldn't match expected type ‘b’
                with actual type ‘OptionList t0 t1’
      ‘b’ is a rigid type variable bound by
          the instance declaration at OptionList.hs:10:10
    Relevant bindings include
      show :: OptionList a b -> String (bound at OptionList.hs:11:9)
    In the pattern: EmptyOpt
    In the pattern: OptionList a EmptyOpt
    In an equation for ‘show’:
        show (OptionList a EmptyOpt) = "{" ++ (show a) ++ "}"

OptionList.hs:12:26:
    Couldn't match expected type ‘a’
                with actual type ‘OptionList t2 t3’
      ‘a’ is a rigid type variable bound by
          the instance declaration at OptionList.hs:10:10
    Relevant bindings include
      show :: OptionList a b -> String (bound at OptionList.hs:11:9)
    In the pattern: EmptyOpt
    In the pattern: OptionList EmptyOpt b
    In an equation for ‘show’:
        show (OptionList EmptyOpt b) = "{" ++ (show b) ++ "}"

UPDATE: OptionList is supposed to be something like a typeless list.

(+:) :: a -> b -> (OptionList a b)
infixr 5 +:
t1 +: t2 = OptionList t1 t2

So, a list like: 0 +: "test" +: True would be defined like OptionList Int (OptionList String (OptionList Bool EmptyOpt)) And would be shown as {0, {"test", {True}}}

3 Answers 3

6

An update for your update. You can make it work if you are willing to turn on some extensions:

{-# LANGUAGE FlexibleInstances #-}

data EmptyOpt = EmptyOpt

data OptionList a b =
  OptionList a b
  deriving (Read)

instance (Show a, Show b) => Show (OptionList a b) where
  show (OptionList a b) = "{ " ++ show a ++ ", " ++ show b ++ " }"

instance {-# OVERLAPPING  #-} (Show a) => Show (OptionList a EmptyOpt) where
  show (OptionList a EmptyOpt) = "{ " ++ show a ++ " }"

(+:) :: a -> b -> (OptionList a b)
infixr 5 +:
t1 +: t2 = OptionList t1 t2

test = 0 +: "test" +: True +: EmptyOpt

But personally I would try to make do with something like

data Option = B Bool | I Int | S String
data OptionsList = Empty | OptionsList Option OptionsList

Your trouble is that the instance head ((Show a, Show b) => Show (OptionList a b)) says that you are implementing Show for OptionList a b where a and b are any types with Show instances, but in your implementation you require that both a and b actually are of type OptionList.

Perhaps you would change your type to be more like an ordinary list:

data OptionList a
  = EmptyOpt
  | OptionList { optListHead :: a
              ,  optListTail :: OptionList a}
  deriving (Read)

Then you can have an instance:

instance (Show a) => Show (OptionList a) where
  show (OptionList a EmptyOpt) = "{" ++ show a ++"}"
  show (OptionList a b) = "{"++ show a ++ ", " ++ show b ++"}"
  show EmptyOpt = ""
Sign up to request clarification or add additional context in comments.

11 Comments

Hah, I had exactly the same idea :)
I don't want that the elements have all the same type.
@BrunoCorrêaZimmermann: That's more or less impossible with Haskell: Haskell is statically typed. You could define a list of Either a b types such that each element is either type a or b. But in Haskell you know in advance the type of elements. If you want this flexibility, you should use a dynamically typed language like Python.
@BrunoCorrêaZimmermann: that is very tricky. Perhaps you can make do with a type data Option = B Bool | I Int | S String and data OptionsList = Empty | OptionsList Option OptionsList? If that doesn't suffice you would have to look into something called heterogenous lists, which are possible to use in Haskell but very nice. I would try to find another solution for your use case.
I would hardly call FlexibleInstances instances frightening. It is one of the most benign extensions - I usually wish it was enabled by default.
|
3

The problem is that in your instance declaration:

instance (Show a, Show b) => Show (OptionList a b) where
    show (OptionList a EmptyOpt) = "{" ++ (show a) ++"}"
    show (OptionList EmptyOpt b) = "{" ++ (show b) ++"}"
    show (OptionList a b) = "{"++ (show a) ++ ", " ++ (show b) ++"}"
    show EmptyOpt = ""

You use dataconstructors. Therefore Haskell derives - correctly - that you actually define a show over OptionList (OptionList c d) (OptionList e f): after all EmptyOpt is a construct of OptionList a b, so you cannot use these as arguments since in the head of your instance you say you are going to define the instance for OptionList a b with generic a and b.

So it is not clear for me what you aim to do; modifying it to:

instance (Show a, Show b, Show c, Show d) => Show (OptionList (OptionList a b) (OptionList c d)) where

would not help either, since the structure is recursive, and you thus would define the instance with infinite recursive depth.

The only thing that seems reasonable to me, is that your data definition is wrong, and should be something like:

data OptionList a = EmptyOpt | OptionList { optListHead :: a, optListTail :: OptionList a }

in which case, you can define it as:

instance Show a => Show (OptionList a) where
    show (OptionList a b) = "{"++ show a ++ ", " ++ show b ++"}"
    show EmptyOpt = ""

or something along these lines.

Comments

0

My idea was to create a type independent list. And this list's elements were supposed to hold any type declared. But I will give up and do something like a C Union:

data Option = OptStr String | OptInt Int | OptBool Bool

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.