Online Book Reader

Home Category

Learn You a Haskell for Great Good! - Miran Lipovaca [51]

By Root 526 0
record syntax:

data Person = Person { firstName :: String

, lastName :: String

, age :: Int

, height :: Float

, phoneNumber :: String

, flavor :: String } deriving (Show)

So instead of just naming the field types one after another and separating them with spaces, we use curly brackets. First, we write the name of the field (for instance, firstName), followed by a double colon (::), and then the type. The resulting data type is exactly the same. The main benefit of using this syntax is that it creates functions that look up fields in the data type. By using record syntax to create this data type, Haskell automatically makes these functions: firstName, lastName, age, height, phoneNumber, and flavor. Take a look:

ghci> :t flavor

flavor :: Person -> String

ghci> :t firstName

firstName :: Person -> String

There’s another benefit to using record syntax. When we derive Show for the type, it displays it differently if we use record syntax to define and instantiate the type.

Say we have a type that represents a car. We want to keep track of the company that made it, the model name, and its year of production. We can define this type without using record syntax, like so:

data Car = Car String String Int deriving (Show)

A car is displayed like this:

ghci> Car "Ford" "Mustang" 1967

Car "Ford" "Mustang" 1967

Now let’s see what happens when we define it using record syntax:

data Car = Car { company :: String

, model :: String

, year :: Int

} deriving (Show)

We can make a car like this:

ghci> Car {company="Ford", model="Mustang", year=1967}

Car {company = "Ford", model = "Mustang", year = 1967}

When making a new car, we don’t need to put the fields in the proper order, as long as we list all of them. But if we don’t use record syntax, we must specify them in order.

Use record syntax when a constructor has several fields and it’s not obvious which field is which. If we make a 3D vector data type by doing data Vector = Vector Int Int Int, it’s pretty obvious that the fields are the components of a vector. However, in our Person and Car types, the fields are not so obvious, and we greatly benefit from using record syntax.

Type Parameters

A value constructor can take some parameters and then produce a new value. For instance, the Car constructor takes three values and produces a car value. In a similar manner, type constructors can take types as parameters to produce new types. This might sound a bit too meta at first, but it’s not that complicated. (If you’re familiar with templates in C++, you’ll see some parallels.) To get a clear picture of how type parameters work in action, let’s take a look at how a type we’ve already met is implemented.

data Maybe a = Nothing | Just a

The a here is the type parameter. And because there’s a type parameter involved, we call Maybe a type constructor. Depending on what we want this data type to hold when it’s not Nothing, this type constructor can end up producing a type of Maybe Int, Maybe Car, Maybe String, and so on. No value can have a type of just Maybe, because that’s not a type—it’s a type constructor. In order for this to be a real type that a value can be part of, it must have all its type parameters filled up.

So if we pass Char as the type parameter to Maybe, we get a type of Maybe Char. The value Just 'a' has a type of Maybe Char, for example.

Most of the time, we don’t pass types as parameters to type constructors explicitly. That’s because Haskell has type inference. So when we make a value Just 'a', for example, Haskell figures out that it’s a Maybe Char.

If we want to explicitly pass a type as a type parameter, we must do it in the type part of Haskell, which is usually after the :: symbol. This can come in handy if, for example, we want a value of Just 3 to have the type Maybe Int. By default, Haskell will infer the type (Num a) => Maybe a for that value. We can use an explicit type annotation to restrict the type a bit:

ghci> Just 3 :: Maybe Int

Just 3

You might not know it, but we used a type that has a type parameter before we used Maybe: the

Return Main Page Previous Page Next Page

®Online Book Reader