Let's assume I have this data type:
data SomeDataType a = SomeDataType a
I want to show its representation to the user (in the console output), so I need a "pretty print" function. I don't want to use show
, because it will return an expression and I just want the value of my type's only field converted to a string.
I expect this behaviour:
>>> let myintdata = SomeDataType (22::Int)
>>> putStrLn $ prettyPrint myintdata
22
>>> let alice = SomeDataType "Alice"
>>> let bob = SomeDataType "Bob"
>>> putStrLn $ prettyPrint alice ++ " loves " ++ prettyPrint bob
Alice loves Bob
So I implement it like this:
prettyPrint :: Show a => SomeDataType a -> String
prettyPrint (SomeDataType x) = show x
It's working fine for numbers, but strings are getting quoted and escaped:
>>> let alice = SomeDataType "Alice"
>>> let bob = SomeDataType "Bob"
>>> putStrLn $ prettyPrint alice ++ " loves " ++ prettyPrint bob
"Alice" loves "Bob"
Also, I want full control on how different content types are converted to strings in the future. So, I'm off to create my own typeclass! It goes like this:
{-# LANGUAGE FlexibleInstances #-}
data SomeDataType a = SomeDataType a
class PrettyPrint a where
prettyPrint :: a -> String
instance {-# OVERLAPPABLE #-} PrettyPrint a where
-- I don't care about this right now,
-- let's learn how to print strings without quotes first!
prettyPrint = const "Stupid Robot"
instance PrettyPrint String where
prettyPrint = id
instance Show a => PrettyPrint (SomeDataType a) where
prettyPrint (SomeDataType x) = prettyPrint x
I'm happy with the first test:
>>> putStrLn $ prettyPrint "No quotes!"
No quotes!
But when I'm trying to pretty print my data type, somehow general instance is being invoked instead of String's:
>>> let alice = SomeDataType "Alice"
>>> let bob = SomeDataType "Bob"
>>> putStrLn $ prettyPrint alice ++ " loves " ++ prettyPrint bob
Stupid Robot loves Stupid Robot
At this point I suspect there is a completely different way to approach this "pretty printing" problem. Is that so? Or am I missing some simple obvious mistake in my code?
In the last instance you are assuming that Show a
and compiler uses only this information to choose appropriate instance for prettyPrint x
.
You can add more information by requiring PrettyPrint a
as a base class:
instance PrettyPrint a => PrettyPrint (SomeDataType a) where
prettyPrint (SomeDataType x) = prettyPrint x
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