[Checkpointing John Goerzen **20070801060128] { hunk ./en/ch13-data.xml 70 - FIXME + One way to make &data; more useful is to have multiple type + constructors. Here's an example: hunk ./en/ch13-data.xml 73 + &data1.hs:color; + + This defined one new type named Color. You can + create a value of type Color by using any of the + three literals Red, Green, or + Blue. There are several reasons this might be + useful as opposed to using something like a &String; to store simple + color names: + + + You are guaranteed that a Color + always represents one of these three values + When you do pattern matching on a + Color, the compiler will warn you if you don't + consider all three possible values + It is possible to hide the implemention of + Color from users when exporting symbols from the + module; you can include Color in the list but + not the three constructors + + + Let's look at some example code that uses the Color: + + &data1.hs:color2; + + That's pretty simple: a function that takes a Color + and converts it to + a &String;. Note that we don't have to deal with the case where the + input to the function is something other than our three colors, because + that can't possibly happen. + + + You use a type defined in this way all the time. Haskell 98 defines + this: + + +data Bool = False | True deriving + (Read, Show, Eq, Ord, Enum, Bounded) + + + As you'll see in the rest of this chapter, many of the core Haskell + features you rely upon are actually defined in the prelude using + &data;. That is, they're not built into the compiler in any special + way. The only thing special about them is that they are loaded for you + by default since they're in the prelude. + + FIXME: have we discussed prelude? + + + + Defining Records + + Custom types need not be defined solely in terms of static data. They + can also take parameters. Let's say that we wanted to take our + color example a new direction and let a user represent arbitrary colors + in the RGB (red, green, blue) colorspace. We could use an + (Int, Int, Int) tuple for this, but to illustrate + records, let's define a new type. + + &color.hs:custom; + + This defines a new type CustomColor and one type + constructor also named CustomColor. This type + constructor, however, requires three parameters, all ∬s. + + + The type constructor here is a unique beast in Haskell. You can use it + as a function that takes three parameters, and it will return to you + one value ot type CustomColor. You can also use it + to perform pattern matching in function or case definitions. + + + Let's use &ghci; to inspect this for a bit: + + + You can see that CustomColor 100 0 50 returns a + single value of type CustomColor. Now you're + probably wondering how to extract the data from that + CustomColor. We use pattern matching to do that. + Here's how: + + &color.hs:extract; + + We used pattern matching to match the CustomColor. + The three ∬s were assigned to red, + green, and blue, and then printed + out. You can see that this worked by using &ghci;: + + &color.ghci:extract; + + This is useful as it is, but when you have half a dozen or more + values to store in your record, it can get annoying to have to match + them all. There's where named fields come in, which we'll discuss + next. + + addfile ./examples/ch13/color.ghci hunk ./examples/ch13/color.ghci 1 +--# custom +:l color.hs +:t CustomColor +:t CustomColor 5 +CustomColor 100 0 50 + +--# extract +color2string (CustomColor 100 0 50) addfile ./examples/ch13/color.hs hunk ./examples/ch13/color.hs 1 +{-- snippet custom --} +data CustomColor = CustomColor Int Int Int + deriving (Eq, Show, Read) +{-- /snippet custom --} + +{-- snippet extract --} +color2string :: CustomColor -> String +color2string (CustomColor red green blue) = + "red: " ++ show red ++ ", green: " ++ show green ++ ", blue: " + ++ show blue +{-- /snippet extract --} hunk ./examples/ch13/data1.hs 18 +{-- snippet color2 --} +describeColor :: Color -> String +describeColor Red = "Rolled out on carpet" +describeColor Blue = "Oceans" +describeColor Green = "Grass" +{-- /snippet color2 --} + + }