[Haskell-beginners] Re: how to define a user datatype consisting
of instances of String?
daniel.is.fischer at web.de
Thu Oct 23 05:48:46 EDT 2008
Am Donnerstag, 23. Oktober 2008 10:51 schrieb Benjamin L.Russell:
> After taking your advice into account, I have rewritten the wine.hs
> program as follows, but am unable to figure out what to write for the
> type constructor for Wine. In particular, I do not understand why the
> user type definition for Wine is "Red Red | White White" instead of
> just "Red | White."
Okay, that was a bit mean, but not intentionally.
In GADT syntax:
data Wine where
Red :: Red -> Wine
White :: White -> Wine
So there is a dataconstructor called Red and also a datatype (I was tempted to
write typeconstructor) called Red and the dataconstructor Red takes an
argument of type Red, similarly for White.
The type Wine is isomorphic to Either Red White, but since that wouldn't give
a good Show instance, we roll our own type.
If we had just
data Wine = Red | White
, the type Wine would have just the two members Red and White (and _|_) and
not have any connection with the types Red and White which give the details
(grape/origin). We need a means to transform a value of type Red into a value
of type Wine, that is a function of type Red -> Wine, the application demands
that that function doesn't lose information, that is best achieved by a
dataconstructor of type Red -> Wine.
Would probably have been less confusing if I called the dataconstructors
RedWine resp. WhiteWine.
> Should I fill out "instance Show Wine where ..." as something similar
> instance Show Wine where
> show Red = ...
> show White = ...
> and then supply a conditional after "show Red = ..." and "show White =
> ...," or do I need to supply something else there?
You have basically two choices, you can say everybody knows which colour the
wines have and use
instance Show Wine where
show (Red w) = show w
show (White w) = show w
or include the colour in the rendered String, for example via deriving Show,
or by declaring your own instance (if you want White PinotNoir rendered as
"White (Pinot Noir)", you would have to do that or write a more complicated
Show instance for White).
If you want to parse values of type Wine in the future, it will be slightly
easier with the dataconstructors included.
> Here's my revised code so far (the "instance Show Wine where ..." part
> is unfinished):
> module Wine where
> data Wine = Red Red | White White
> data Red = Merlot | Syrah | Port
> data White = SauvignonBlanc | Riesling | PinotNoir
> data Entree = KobeBeef | LemonChicken | SteamedSalmon deriving (Eq,
> Enum, Bounded)
> data SideDish = ButteredPotatoes | BrieCheese | GreekSalad deriving
> (Eq, Enum, Bounded)
> instance Show Wine where ...
> instance Show Red where
> show Merlot = "Merlot"
> show Syrah = "Syrah"
> show Port = "Port"
> instance Show White where
> show SauvignonBlanc = "Sauvignon Blanc"
> show Riesling = "Riesling"
> show PinotNoir = "Pinot Noir"
> instance Show Entree where
> show KobeBeef = "Kobe Beef"
> show LemonChicken = "Lemon Chicken"
> show SteamedSalmon = "Steamed Salmon"
> instance Show SideDish where
> show ButteredPotatoes = "Buttered Potatoes"
> show BrieCheese = "Brie Cheese"
> show GreekSalad = "Greek Salad"
> selectWine :: Entree -> SideDish -> Wine
> selectWine KobeBeef sd
> = case sd of
> GreekSalad -> White SauvignonBlanc
> _ -> Red Merlot
> selectWine LemonChicken sd
> = case sd of
> BrieCheese -> White Riesling
> _ -> Red Syrah
> selectWine SteamedSalmon sd
> = case sd of
> ButteredPotatoes -> White PinotNoir
> _ -> Red Port
> options :: [(Entree,SideDish,Wine)]
> options = [(e,s,selectWine e s) | e <- [minBound .. maxBound], s <-
> [minBound .. maxBound]]
> -- Benjamin L. Russell
P.S.: Could I have a Syrah with my beef and potatoes?
More information about the Beginners