
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?