Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell: How to pretty print a string without quotes?

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?

like image 704
Sergey Mitskevich Avatar asked Jan 06 '16 05:01

Sergey Mitskevich


1 Answers

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
like image 79
max taldykin Avatar answered Nov 15 '22 02:11

max taldykin