I have some types with custom Show
instances defined. They are structured like this:
data TopLevel = TopLevel SndLevel
data SndLevel = SndLevel Int
instance Show SndLevel where
show (SndLevel i) = "SndLevel: \n\t" ++ (show i)
My Show
instance for SndLevel
produces nice looking strings that look like the following when they appear in my output:
SndLevel:
5
I would like to create a Show
instance for topLevel
that causes TopLevel (SndLevel 5)
to look like this when printed to the terminal:
TopLevel
SndLevel
5
I was hoping to find a function built into Haskell that would add "\t"
at the front of a string and before each location where "\n"
appears in that string.
The best solution I found would go along the lines of the answer in this post. In this case, I would replace "\n"
with "\t\n"
.
I assume I'm not the first person to need Show instances for hierarchically organized data in Haskell, so I would like to know if there is a more idiomatic way to get this done. Is there some better solution to my problem?
p.s: I realize this kind of printing is not the best for the example datatypes I use above. The real datatypes I want to write instances for are product types, and so they don't read well when stretched out on one line. With that in mind, if there is a popular way to deal with this kind of problem without newlines and tabs, that could also solve my problem.
We can solve this by using lines :: String -> [String]
and unlines :: [String] -> String
to move from a String
to a list of String
s and back.
In between, we can make use of map :: (a -> b) -> [a] -> [b]
to prepend all lines (a String
is a list of Char
s) with a tab, like:
indent :: String -> String
indent = unlines . map ('\t' :) . lines
For example:
Prelude> indent (show (SndLevel 5))
"\tSndLevel: \n\t\t5\n"
We can use this in our defintion of Show
for both SndLevel
and TopLevel
like:
instance Show SndLevel where
show (SndLevel n) = "SndLevel:" ++ '\n' : indent (show n)
instance Show TopLevel where
show (TopLevel n) = "TopLevel:" ++ '\n' : indent (show n)
This thus gives us:
Prelude> print (TopLevel (SndLevel 5))
TopLevel:
SndLevel:
5
That being said, a Show
is usually used to show a representation of the object that can usually be "injected" back inh the compiler/interpreter. The idea of using indentation is not bad at all, but perhaps it makes sence to define your own typeclass for that. You could make that typeclass more efficient by using a parameter that is passed and updated, that keeps track of the indentation level.
There are furthermore several "pretty printing" libraries [Reddit] that can print the structure of an object nicely. So instead of "reinventing the wheel", it might be worth using one of the packages listed on the Reddit page.
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