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

Benjamin L.Russell DekuDekuplex at Yahoo.com
Thu Oct 23 06:19:32 EDT 2008

On Thu, 23 Oct 2008 11:48:46 +0200, Daniel Fischer
<daniel.is.fischer at web.de> wrote:

>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.

Thank you.  That makes the Wine much clearer ;-) .

>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.

So perhaps I should rewrite the type definitions for Red and White as

data Red = Syrah | Merlot | Port deriving (Eq, Show)
data White = SauvignonBlanc | Riesling | PinotNoir deriving (Eq, Show)

Alternatively (adapted from an example provided by Dirk Thierbach in
the thread "seeking helpful links," dated "Tue, 21 Oct 2008 16:33:41
-0700 (PDT)," on comp.lang.haskell), perhaps the following?

  type Entree = String
  type SideDish = String
  type Wine = String

  wine :: Entree -> SideDish -> Wine
  wine "Kobe Beef"    "Buttered Potatoes"       = "Syrah"
  wine "Kobe Beef"    "Brie Cheese"  = "Syrah"
  wine "Kobe Beef"    "Greek Salad"             = "Sauvignon Blanc"
  wine "Lemon Chicken" "Buttered Potatoes"       = "Merlot"
  wine "Lemon Chicken" "Brie Cheese"  = "Sauvignon Blanc"
  wine "Lemon Chicken" "Greek Salad"             = "Merlot"
  wine "Steamed Salmon"    "Buttered Potatoes"       = "Sauvignon
  wine "Steamed Salmon"    "Brie Cheese"  = "Port"
  wine "Steamed Salmon"    "Greek Salad"             = "Port"

  wines :: [Entree] -> [SideDish] -> [(Entree, SideDish, Wine)]
  wines entrees sideDishes = [(e, s, wine e s) | e <- entrees, s <-

>Bon Appetit,
>P.S.: Could I have a Syrah with my beef and potatoes?

Certainly; here is your Syrah with your beef and potatoes.  Bon
appetit ;-) :

module Wine where 
data Wine = Red Red | White White
data Red = Syrah | Merlot | 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 
    show (Red w) = show w
    show (White w) = show w

instance Show Red where
    show Syrah = "Syrah"
    show Merlot = "Merlot"
    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 Syrah
selectWine LemonChicken sd
    = case sd of
	BrieCheese -> White Riesling
	_ -> Red Merlot
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]]

Here's your new menu:

*Wine> :l wine2.hs
[1 of 1] Compiling Wine             ( wine2.hs, interpreted )
Ok, modules loaded: Wine.
*Wine> options
[(Kobe Beef,Buttered Potatoes,Syrah),(Kobe Beef,Brie
Cheese,Syrah),(Kobe Beef,Gr
eek Salad,Sauvignon Blanc),(Lemon Chicken,Buttered
Potatoes,Merlot),(Lemon Chick
en,Brie Cheese,Riesling),(Lemon Chicken,Greek Salad,Merlot),(Steamed
ered Potatoes,Pinot Noir),(Steamed Salmon,Brie Cheese,Port),(Steamed
k Salad,Port)]

-- Benjamin L. Russell

More information about the Beginners mailing list