I come from imperative programming and I am learning Haskell. I have following data types:
newtype Prename = Prename String deriving (Show)
newtype Surname = Surname String deriving (Show)
data Employment = Employed | Unemployed
data Person = P Prename Surname Employment
jondoe = P (Prename "John") (Surname "Doe") Employed
How can I access the Strings of Prename
and Surname
without the constructors. Currently I get the following output:
show jondoe
"P (Prename\"John\") (Surname\"Doe\") (Employed)"
but I want it to be
show jondoe
"John Doe"
I am getting very frustrated because it seems like such a simple thing to, how can I achieve this?
CodePudding user response:
show
is not for getting pretty output. It is specifically supposed to produce valid Haskell code. Now, "John Doe"
certainly is syntactically valid, but it doesn't have the right type.
That said, I personally find it perfectly ok to base a Show
instance on custom smart constructors, which would make it more readable. For example, you could have
employee :: Prename -> Surname -> Person
employee pn sn = P pn sn Employed
nonworker :: Prename -> Surname -> Person
nonworker pn sn = P pn sn Unemployed
Furthermore, you may ask yourself whether Prename
and Surname
really need to be newtypes
. If you simply make them
type Prename = String
type Surname = String
then they can be directly printed as... well, strings. Now you could write a Show
instance
instance Show Person where
showsPrec p (P pn sn Employed)
= showParen (p>9)
$ ("employee " )
. showsPrec 11 pn
. showsPrec 11 sn
showsPrec p (P pn sn Unemployed)
= ...
CodePudding user response:
There are a few ways to do this. One way is to write a function that writes the name to the terminal as follows:
writeName :: Person -> IO ()
writeName (P (Prename p) (Surname s) _) = putStrLn (p " " s)
λ> writeName jondoe
John Doe
Another way is a function that returns the concatenated full name as a string:
getFullname :: Person -> String
getFullname (P (Prename p) (Surname s) _) = p " " s
getFullname :: Person -> String
getFullname (P (Prename p) (Surname s) _) = p " " s
A third way is to implement an instance of Show
for Person
as follows:
instance Show Person where
show (P (Prename p) (Surname s) _) = p " " s
λ> show jondoe
"John Doe"
But to be honest, I'm not sure if implementing a Show
instance in this way is a good idea because you loose the Employment
information. Having a custom function that explicitly says what it does appears the better way to me.