data: product types

Contents
Declare a type
Several fields
Deriving
Types inside types

Declare a type

A data declaration names a type and the constructor that builds its values. The constructor is a function, so it can be partially applied like any other:

data Point = Point Double Double deriving (Show, Eq) origin :: Point origin = Point 0.0 0.0

The type name and the constructor name live in different namespaces, so reusing the word Point for both is legal and idiomatic. A value of this type carries two numbers and nothing else.

Several fields

A constructor with three arguments is a product of three types. The function that consumes it destructures all three at once:

data Segment = Segment Point Point deriving (Show) shiftX :: Double -> Point -> Point shiftX d (Point x y) = Point (x + d) y move :: Double -> Segment -> Segment move d (Segment a b) = Segment (shiftX d a) (shiftX d b)

Nested patterns are the reason the type is useful: the shape of the value is written once and the compiler checks it.

Deriving

Three classes cover most needs, and the compiler writes all of them. Equality compares field by field, and the printed form mirrors the declaration:

data Point = Point Double Double deriving (Show, Eq, Ord) -- show (Point 1.0 2.0) == "Point 1.0 2.0" -- Point 1.0 2.0 == Point 1.0 2.0 == True

Deriving Ord on a product compares the first field, then the second. That is a lexicographic order, which is occasionally useful and often surprising.

Types inside types

A field may be any type, including another type you declared or a container of one. This is how small models grow:

data Person = Person String Int deriving (Show) data Team = Team String [Person] deriving (Show) team = Team "core" [Person "Ada" 36, Person "Alan" 41]

Positional fields stop being readable at about three of them, which is where records take over in lesson 26.

Next: data: sum types

Article author: Arthur Isaev

Related articles
Haskell
Haskell course: zero to hero in 50 lessons
What is Haskell and why it matters
Install the toolchain with GHCup
GHCi: the interactive shell
Your first program
Values with let and where
Types and type signatures
Functions and application
Currying and partial application
Operators, sections, and fixity
if, guards, and pattern guards
case expressions
Pattern matching
Tuples
Lists
Ranges and enumeration
List comprehensions
Recursion replaces loops
map, filter, and foldr
Lambdas and composition
Type classes
Parametric polymorphism
Maybe and null safety
Either and recoverable errors
data: product types
data: sum types
Records
newtype and type synonyms
Recursive data: binary trees
Functor
Applicative
Monad
do notation
IO and purity
Files and IO
Modules and imports
Cabal projects
Dependencies
Testing with HUnit
Property testing with QuickCheck
Laziness and infinite lists
Strictness and space leaks
Folds
Monoids
Traversable
Monad transformers
Errors and exceptions
Concurrency
Parsing with Megaparsec
Capstone: a todo CLI
Hero roadmap: the whole course on one page

Search this site

Channel @aofeed Chat @aofeedchat

Contacts and cooperation:
I recommend our hosting beget.com
Write to info@aredel.com if you:
1. Want to write an article for our site or translate an article into your native language.
2. Want to place thematically relevant ads on the site.
3. Ads on my site pass maximum censorship. If you see an ad block unsuitable for school-age children, shocking or misleading - please contact us by e-mail
4. Found a mistake, inaccuracy, bug, etc. on the site. ... .......
5. Articles can be shared on social media by clicking a network icon: