Creating Custom Data Types
Creating a data type with value constructor parameters
Section titled “Creating a data type with value constructor parameters”Value constructors are functions that return a value of a data type. Because of this, just like any other function, they can take one or more parameters:
data Foo = Bar String Int | Biz StringLet’s check the type of the Bar value constructor.
:t Barprints
Bar :: String -> Int -> Foowhich proves that Bar is indeed a function.
Creating variables of our custom type
Section titled “Creating variables of our custom type”let x = Bar "Hello" 10let y = Biz "Goodbye"Creating a data type with type parameters
Section titled “Creating a data type with type parameters”Type constructors can take one or more type parameters:
data Foo a b = Bar a b | Biz a bType parameters in Haskell must begin with a lowercase letter. Our custom data type is not a real type yet. In order to create values of our type, we must substitute all type parameters with actual types. Because a and b can be of any type, our value constructors are polymorphic functions.
Creating variables of our custom type
Section titled “Creating variables of our custom type”let x = Bar "Hello" 10 -- x :: Foo [Char] Integerlet y = Biz "Goodbye" 6.0 -- y :: Fractional b => Foo [Char] blet z = Biz True False -- z :: Foo Bool BoolCreating a simple data type
Section titled “Creating a simple data type”The easiest way to create a custom data type in Haskell is to use the data keyword:
data Foo = Bar | BizThe name of the type is specified between data and =, and is called a type constructor. After = we specify all value constructors of our data type, delimited by the | sign. There is a rule in Haskell that all type and value constructors must begin with a capital letter. The above declaration can be read as follows:
Define a type called Foo, which has two possible values: Bar and Biz.
Creating variables of our custom type
Section titled “Creating variables of our custom type”let x = BarThe above statement creates a variable named x of type Foo. Let’s verify this by checking its type.
:t xprints
x :: FooCustom data type with record parameters
Section titled “Custom data type with record parameters”Assume we want to create a data type Person, which has a first and last name, an age, a phone number, a street, a zip code and a town.
We could write
data Person = Person String String Int Int String String StringIf we want now to get the phone number, we need to make a function
getPhone :: Person -> IntgetPhone (Person _ _ _ phone _ _ _) = phoneWell, this is no fun. We can do better using parameters:
data Person' = Person' { firstName :: String , lastName :: String , age :: Int , phone :: Int , street :: String , code :: String , town :: String }Now we get the function phone where
:t phonephone :: Person' -> IntWe can now do whatever we want, eg:
printPhone :: Person' -> IO ()printPhone = putStrLn . show . phoneWe can also bind the phone number by Pattern Matching:
getPhone' :: Person' -> IntgetPhone' (Person {phone = p}) = pFor easy use of the parameters see RecordWildCards