Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pattern matching of instance implementation

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}}}

like image 822
bzim Avatar asked Nov 03 '25 01:11

bzim


1 Answers

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 = ""
like image 175
adamse Avatar answered Nov 04 '25 17:11

adamse