[Haskell-beginners] Re: how to define a user datatype consisting of instances of String?

Daniel Fischer 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
> to
>
> 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
>

Bon Appetit,
Daniel

P.S.: Could I have a Syrah with my beef and potatoes?


More information about the Beginners mailing list