[More revision. Bryan O'Sullivan **20080116235031] { hunk ./en/ch04-defining-types.xml 22 - name must start with a capital letter.) The string - Section is the name of the value - constructor we'll apply to create a value of this - type. (As with a type constructor, a value constructor's name - must start with a capital letter.) Finally, the - Int and String that follow are the - components of the type. A component serves - the same purpose in Haskell as a field in a structure or class - would in another language: it's a slot where we can place a - value. + name, and hence a type constructor, must start with a capital + letter.) The string Section is the name of the + value constructor we'll apply to create a + value of this type. (As with a type constructor, a value + constructor's name must start with a capital letter.) + + Finally, the Int and String that + follow are the components of the type. A + component serves the same purpose in Haskell as a field in a + structure or class would in another language: it's a + slot where we can put a value. We'll often refer + to components as fields. hunk ./en/ch04-defining-types.xml 60 - Remember the fp variable we defined? Here - it is. + Remember the fpSection variable we + defined? Here it is. hunk ./en/ch04-defining-types.xml 65 - A constructor serves as both a function for creating a value - and a tag identifying what type of value we have. - The value that &ghci; prints is telling us that we have created - a value with the tag BookSection, with the given - values in each slot. (By the way, this is why we - had to add deriving (Show) to the definition of our - type; without that, &ghci; would print an error message, telling - us that it doesn't know how to print a value of this - type.) - hunk ./en/ch04-defining-types.xml 88 - From Haskell's perspective, then, a value - constructor is just another function, one that happens to return - a value of the type we want to construct. + We can treat a value constructor as just another + function, one that happens to create and return a new value of + the type we desire. + + + Naming types and values + + When we introduced the type BookSection, we + deliberately chose to give the type constructor + BookSection a different name from the value + constructor Section, purely to make it obvious + which was which. + + However, in Haskell, the names of types and values occupy + two independent namespaces, so there is + no ambiguity if we give a type constructor and a value + constructor the same name. + + &BookSection.hs:BookChapter; + + This definition says that the type named + BookChapter has a value constructor that is also + named BookChapter. Since a type signature + doesn't contain value names, and a normal expression doesn't + contain type names, it's always clear from the context in + which we use a name whether that name refers to a type or a + value. + + In fact, not only is it legal for a + value constructor to have the same name as its type + constructor, it's normal: you'll see this + all the time in regular Haskell code. + hunk ./en/ch04-defining-types.xml 126 - The Bool type that we introduced earlier is the - simplest example of a sort of type called an algebraic - data type. An algebraic data type has a fixed set - of possible values, each of which is identified by a distinct - constructor. + The Bool type that we introduced + earlier is the simplest example of a category of type called an + algebraic data type. An algebraic data type + has several value constructors. hunk ./en/ch04-defining-types.xml 131 - The use of the word algebraic simply - indicates that the components of an algebraic data type are used - together. + &Bool.hs:Bool; hunk ./en/ch04-defining-types.xml 134 - constructors, True and False. Each - constructor is separated by a | character, - which we can read as or. These are usually - referred to as alternatives or cases. + value constructors, True and False. + Each value constructor is separated in the definition by a + | character, which we can read as + or. The different value constructors are usually + referred to as alternatives or + cases. hunk ./en/ch04-defining-types.xml 141 - &Bool.hs:Bool; + + Why <quote>algebraic</quote>? + + The use of the word algebraic for + describing these data types comes from abstract + algebra. + + Although the phrase algebraic data type is + long, we're being careful to avoid using the acronym + ADT instead. That acronym is already widely + understood to stand for abstract + data type, which is quite different. + hunk ./en/ch04-defining-types.xml 155 - Each constructor of an algebraic type can take - zero or more arguments; the numbers and types of the arguments - accepted by each constructor are independent. For example, + Each of an algebraic data type's value + constructors can take zero or more arguments. As an example, hunk ./en/ch04-defining-types.xml 158 - operating system, where old releases were monolithic, and newer - releases have service pack levels denoting major - updates after their initial releases. + operating system. hunk ./en/ch04-defining-types.xml 160 - &OsVersion.hs:WindowsVersion; + &OsVersion.hs:WindowsVersion; hunk ./en/ch04-defining-types.xml 162 - The alternatives that represent older releases don't need - arguments, but those for the newer releases need an - Int to represent the patch level. + The alternatives that represent older releases + don't need arguments, but we use an Int to + represent a service pack level for newer releases. + + &osversion.ghci:types; hunk ./en/ch04-defining-types.xml 172 - Algebraic data types provide a single structuring - mechanism in instances where other languages have several - different building blocks. Here are some analogues from C and - C++, which might make it clearer what we can do with algebraic - data types. + Algebraic data types provide a uniform way to + describe data types. Other languages often need several + different features to cover the same ground. Here are some + analogues from C and C++, which might make it clearer what we + can do with algebraic data types, and how they relate to + concepts that might be more familiar. + + + The struct + + With just one constructor, an algebraic data + type is similar to a tuple: it groups related values + together. It corresponds to a struct in C or + C++, and its components correspond to the fields of a + struct. Here's a C equivalent of the + BookSection type that we defined + earlier. + + &types.c:book_section; + + The main difference between the two is that the fields + in the Haskell type are anonymous and positional. hunk ./en/ch04-defining-types.xml 195 - With just one constructor, an algebraic data type groups - related values into one, and gives that value an identity - distinct from other types. It corresponds to a - struct in C or C++, and its components correspond to the - fields of a struct. Here's such a struct. + &BookSection.hs:BookSection; hunk ./en/ch04-defining-types.xml 197 - &types.c:coord; + By positional, we mean that the + section number is in the first field of the Haskell type, + and the title is in the second. In , we'll see how to access the + fields of the BookSection type. hunk ./en/ch04-defining-types.xml 203 - And here's an equivalent type in Haskell. + hunk ./en/ch04-defining-types.xml 205 - &SimpleTypes.hs:Coord; + + The union hunk ./en/ch04-defining-types.xml 208 - The only significant difference is that the fields in the - Haskell type are anonymous and positional. In , we'll see how to use names - to access the fields of the Coord type. + If an algebraic data type has multiple + alternatives, we can think of it as similar to a + union in C or C++. A big difference between + the two is that a union doesn't tell us which alternative is + actually present; we have to record which alternative we're + using ourselves, usually in another field of a struct. This + means that unions can be sources of nasty bugs, where our + notion of which alternative we should be using is + incorrect. hunk ./en/ch04-defining-types.xml 218 - If an algebraic data type has multiple alternatives, we - can think of it as similar to a union in C or - C++. A big difference between the two is that a union doesn't - tell us which alternative is actually present; we have to - record which alternative we're using ourselves, usually in - another field of a struct. This means that unions can - sometimes be sources of bugs, where our notion of which - alternative we should be using is incorrect. + With an algebraic data type, Haskell stores + the constructor that we use in the value that we create, so + we don't need to manually sock it away somewhere + else. + hunk ./en/ch04-defining-types.xml 224 - With an algebraic data type, Haskell stores the - constructor that we use in the value that we create, so we - don't need to manually sock it away somewhere else. + + The enum hunk ./en/ch04-defining-types.xml 227 - Algebraic data types also serve where we'd use - an enum in C or C++, to represent a range of - discrete symbolic values. Such algebraic data types are - sometimes referred to as enumeration types. Here's an example - from C. + Algebraic data types also serve where we'd use + an enum in C or C++, to represent a range of + discrete symbolic values. Such algebraic data types are + sometimes referred to as enumeration types. Here's an + example from C. hunk ./en/ch04-defining-types.xml 233 - &types.c:roygbiv; + &types.c:roygbiv; hunk ./en/ch04-defining-types.xml 235 - And here's a Haskell equivalent. + And here's a Haskell equivalent. hunk ./en/ch04-defining-types.xml 237 - &SimpleTypes.hs:Roygbiv; + &SimpleTypes.hs:Roygbiv; hunk ./en/ch04-defining-types.xml 239 + hunk ./examples/ch04/BookSection.hs 3 - deriving (Show) + deriving (Show) hunk ./examples/ch04/BookSection.hs 7 -fp = Section 5 "Functional programming" +fpSection = Section 5 "Functional programming" hunk ./examples/ch04/BookSection.hs 10 +{-- snippet BookChapter --} +data BookChapter = BookChapter Int String [BookSection] + deriving (Show) +{-- /snippet BookChapter --} + hunk ./examples/ch04/SimpleTypes.hs 1 -{-- snippet Coord --} -data Coord = Coord Int Int -{-- /snippet Coord --} - hunk ./examples/ch04/SimpleTypes.hs 2 -coordX (Coord x y) = x -coordY (Coord x y) = y +sectionNumber (BookSection n t) = n +sectionTitle (BookSection n t) = t hunk ./examples/ch04/SimpleTypes.hs 7 -nicerX (Coord x _) = x -nicerY (Coord _ y) = y +nicerNumber (BookSection n _) = n +nicerTitle (BookSection _ t) = t hunk ./examples/ch04/booksection.ghci 5 -fp -:type fp +fpSection +:type fpSection hunk ./examples/ch04/booksection.ghci 18 -:info MyType +:info BookSection addfile ./examples/ch04/osversion.ghci hunk ./examples/ch04/osversion.ghci 1 +:load OsVersion + +--# types +:type Win95 +:type WinXP hunk ./examples/ch04/types.c 1 -/** snippet coord */ -struct address { - int x; - int y; +/** snippet book_section */ +struct book_section { + int number; + char *name; hunk ./examples/ch04/types.c 6 -/** /snippet coord */ +/** /snippet book_section */ }