Data constructor 2026-10-31
A named way to construct one alternative of an algebraic data type. In data Tree a = One a | Two (Tree a) (Tree a), One has type signature a -> Tree a and Two has type signature Tree a -> Tree a -> Tree a. They construct values; the type constructor Tree instead constructs types from a type argument.
Data type 2026-10-31
A classification of program values together with the operations permitted on them. An algebraic data type describes values by data constructors; a function type describes acceptable arguments and produced results.
An unlabelled exception can be represented by an algebraic data type with successful and failed alternatives, sequenced inside a base computational monad. Sequencing skips the next computation after failure; a handler runs an alternative computation. The base effects already performed need not be undone.
Mutual recursion 2026-10-31
Two or more functions are mutually recursive when their definitions call one another in a cycle. Two algebraic data types can likewise be mutually recursive when constructors of each refer to the other. For alternating sequences Zig a b and Zag b a, descending one constructor exchanges the type parameters; a pair of mapping functions must exchange its arguments correspondingly. A mutually recursive fold may have two independent result types : its handlers have types a -> s -> r and b -> r -> s, with empty results of types r and s. Equality of the two result types is not required by type inference.
There is one undifferentiated exception, so use the two alternatives of the Haskell algebraic data type Maybe: Just x succeeds and Nothing fails. A suitable exception monad transformer is:
type ExT m a = m (Maybe a)

result :: Monad m => a -> ExT m a
result x = resultM (Just x)

bind :: Monad m => ExT m a -> (a -> ExT m b) -> ExT m b
bind p f = bindM p (\r -> case r of
  Nothing -> resultM Nothing
  Just x  -> f x)

orelse :: Monad m => ExT m a -> ExT m a -> ExT m a
orelse p q = bindM p (\r -> case r of
  Nothing -> q
  Just x  -> resultM (Just x))

failure :: Monad m => ExT m a
failure = resultM Nothing
The distinction between bindM and bind matters. The handler must inspect the failed alternative using the base computational monad; the transformed bind would propagate failure without running that inspection. The alternative computation q runs only after p returns Nothing; any effects already performed by the base computational monad remain subject to that base's semantics.
Left identity follows by selecting Just x. Right identity follows because either alternative is passed back to resultM. For associativity, base associativity exposes the first alternative: Nothing propagates through both remaining steps; Just x runs f x, with its Nothing and Just alternatives treated identically on both sides. Thus this representation also satisfies the monad laws.
A string data type suffices for a name, an algebraic data type for the recorded sex, and a triple of integers for a date. Use a constructor for Person so that selectors are unambiguous in Haskell:
type Name = String
data Sex = Female | Male deriving (Eq, Show)
data Date = Date { day :: Int, month :: Int, year :: Int }
  deriving (Eq, Show)
data Person = Person { name :: Name, sex :: Sex, born :: Date }
  deriving (Eq, Show)
type BirthCertificate = (Person, Person, Person)
type Database = [BirthCertificate]
Dates have the precondition that their fields form a valid calendar date. This simple database representation assumes the triple of identifying fields distinguishes the recorded individuals; a production database would normally add a stable identifier to distinguish namesakes. The two constructors for Sex model the two recorded values used by this exercise. In mathematical notation,
An empty constructor and a constructor containing a label and two subtrees give a polymorphic algebraic data type:
data STree a = Empty | Node (STree a) a (STree a)
  deriving (Eq, Show)
The binary search tree invariant is at each Node left x right, together with the same invariant recursively in both subtrees. Labels are distinct because the representation is of a set. The declaration itself needs no ordering constraint; operations that compare labels require Ord a in their type signatures.
In executable Haskell, the algebraic data type declaration uses data, rather than the printed type. A leaf of a rooted tree contributes False; a fork contributes True followed by its left and right subtrees in that order.
data Tree = Leaf | Fork Tree Tree

preorder :: Tree -> [Bool]
preorder Leaf       = [False]
preorder (Fork l r) = True : (preorder l ++ preorder r)
This is a preorder traversal of a full binary tree, including the leaves. Structural induction proves correctness: the leaf of a rooted tree case has precisely one output, and the fork case concatenates the correct preorder traversals of its two subtrees after its own marker.
An equivalent version avoids repeatedly copying the left list through list concatenation:
preorder t = walk t []
  where
    walk Leaf rest       = False : rest
    walk (Fork l r) rest = True : walk l (walk r rest)
Its strengthening is walk t rest = preorder t ++ rest. Each vertex constructs one list cell, so this version has linear time complexity. The concise result is
Use pattern matching on the two data constructors, concatenating the left subtree's inorder traversal, the root label, and the right subtree's inorder traversal:
data Tree = Leaf | Fork Tree Int Tree

inorder :: Tree -> [Int]
inorder Leaf = []
inorder (Fork l x r) = inorder l ++ [x] ++ inorder r
Here Leaf represents the empty binary tree, rather than a labelled leaf. The printed declaration uses type; an executable Haskell algebraic data type requires data, as above. By structural induction, the two equations return precisely the prescribed inorder traversal:
Only the first constructor needs to be inspected:
headZig :: Zig a b -> a
headZig (Cins x _) = x
headZig Nil = error "headZig: empty input"

headZag :: Zag a b -> a
headZag (Cans x _) = x
headZag Nal = error "headZag: empty input"
The first type parameter is the type of the first element in either algebraic data type. The source examples therefore return 1 and "C", respectively. These functions are partial at empty inputs, as allowed by the stated nonempty-input requirement.
Map each current first-position value with the first function, then swap the functions when descending to the other algebraic data type:
mapZig :: (a -> c) -> (b -> d) -> Zig a b -> Zig c d
mapZig _ _ Nil = Nil
mapZig f g (Cins x zs) = Cins (f x) (mapZag g f zs)

mapZag :: (a -> c) -> (b -> d) -> Zag a b -> Zag c d
mapZag _ _ Nal = Nal
mapZag f g (Cans x zs) = Cans (f x) (mapZig g f zs)
All four type variables are independent: mapping may change both element types. There is no Enum or numeric constraint on the mapping functions themselves; constraints arise only from particular arguments such as succ or (+2). The mutual recursion preserves every constructor and applies the intended function at each alternating position. The results are Cins 3 (Cans 'B' (Cins 4 Nal)) and Cans "D" (Cins True (Cans "E" Nil)), respectively.
Use the symmetric tree fold equations for the other algebraic data type:
foldZag (fZag,eZag) (fZig,eZig) Nal = eZag
foldZag (fZag,eZag) (fZig,eZig) (Cans x z) =
  fZag x (foldZig (fZig,eZig) (fZag,eZag) z)
The most general type signatures, using the same schematic variable names independently for each function, are
foldZig :: (a -> s -> r, r) -> (b -> r -> s, s)
        -> Zig a b -> r
foldZag :: (a -> s -> r, r) -> (b -> r -> s, s)
        -> Zag a b -> r
For foldZig, the first empty value has type r, so the first combining function must return r. Its label argument has type a. The recursively folded tail has some independent result type s, giving a -> s -> r. The second combining function consumes a b label and an r result and returns s, giving b -> r -> s. The second empty value has type s. Swapping the two handler pairs and the label types makes the recursive call well-typed. The identical argument applies to foldZag.
The two result types need not coincide. For example, one handler can return an integer and the other a list; forcing both results to have one type would lose parametric polymorphism allowed by the definitions.
Map over the optional payload, preserving failure:
mapMaybe :: (a -> b) -> Maybe a -> Maybe b
mapMaybe _ Nothing = Nothing
mapMaybe f (Just x) = Just (f x)
This is the optional-value mapping operation, equivalent to fmap for Maybe. The question's local name is distinct from the library function Data.Maybe.mapMaybe, which filters and maps an entire list. The algebraic data type keeps absence separate from every ordinary payload value.
A type synonym is a name for an existing type expression, introduced with type, for example type Name = String. It improves documentation and makes type signatures easier to maintain. It creates no new distinct type: a synonym and its expansion remain interchangeable. An algebraic data type declared with data or newtype has a different role.
Tree is a type constructor, taking the element type parameter a to the algebraic data type Tree a. It is not a value and has no ordinary value-level function type; its kind of a type is * -> *. The other names are data constructors with polymorphic type signatures:
One :: a -> Tree a
Two :: Tree a -> Tree a -> Tree a
One constructs a leaf-labelled binary tree with one leaf; Two joins two such trees under a new internal node. Unlike a general binary tree representation with empty child slots, this representation has no empty tree.[ref]
Use a type synonym for names and an algebraic data type with the two teams and their goals in the given positional order:
type Team = String
data Match = Match Team Int Team Int
Team is a synonym, not a new runtime wrapper. Match on the left is the type constructor, while the same spelling on the right is a data constructor in a different namespace. Its value-level type signature is Match :: Team -> Int -> Team -> Int -> Match.