I'm very new to Haskell and created this class
class Printable a where
toString :: a -> String
And two of its instances
instance Printable Bool where
toString x | x == True = "true"
| x == False = "false"
instance Printable () where
toString x = "unit type"
They work just fine, and now I want to create an instance that would take two parameters, but I'm having troubles. What I created so far is
instance (Printable a, Printable b) => Printable (a, b) where
toString x | fst x == True = "(true,unit type)"
But now I get the error
Couldn't match expected type ‘a’ with actual type ‘Bool’
which is reasonable, but when I replace a with Bool I also get an error. How can I make it work in the first place, and can I restrict the types for a and b - for example, what if I want a to always be Bool and b to always be ()?
You wrote an instance where you write that for a tuple (a, b), the tuple is Printable in case the items a and b are Printable. But that does not mean that a or b are Bools, or units.
You may think that - like in many languages - the (==) operator works on any two types, but in Haskell (==) has type (==) :: Eq a => a -> a -> Bool, so it is a function where the left and the right operand have the same type. So we can not use x == True, unless x is a Bool.
We do not need these guards. What we need to do is call the toString function of the operands, so:
instance (Printable a, Printable b) => Printable (a, b) where
toString (x,y) = "(" ++ toString x ++ "," ++ toString y ++ ")"
We can also replace [x] ++ with x : ... so we can rewrite it to:
instance (Printable a, Printable b) => Printable (a, b) where
toString (x,y) = '(' : toString x ++ ',' : toString y ++ ")"
EDIT: in case you want a to be always a Bool, you can write:
instance Printable b => Printable (Bool, b) where
toString (x,y) = '(' : toString x ++ ',' : toString y ++ ")"
You can of course now add guards, pattern matching, or some other method to discriminate between x == True and x == False, but I advice you not to do this, since this violates the DRY principle: Don't Repeat Yourself.
Just because a has a Printable instance doesn't mean you can assume a ~ Bool, so x == True fails.
You should be using pattern matching instead of equality, though, which would sidestep the issue.
class Printable a where
toString :: a -> String
instance Printable Bool where
toString True = "true"
toString False = "false"
instance Printable () where
toString () = "unit type"
Your tuple instance should then make use of the fact that a and b are both Printable. You only need to pattern-match on the constructor, not the individual components.
instance (Printable a, Printable b) => Printable (a, b) where
toString (x, y) = "(" ++ toString x ++ "," ++ toString y ++ ")"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With