# Sum and Product Types

There are generally two data types in FP languages. These are otherwise known as Algebraic Data Types (ADTs):

• Sum types (corresponds to addition)
• Product types (corresponds to multiplication)

These are better explained in this video as to how they get their names.

The simplest form of them are `Either` and `Tuple`

``````-- sum
data Either a b   -- a value of htis type is an `a` value OR  a `b` value
= Left a
| Right b

-- product        -- a value of htis type is an `a` value AND a `b` value
data Tuple a b
= Tuple a b

-- both           --  a value of this type is one of the following:
data These a b
= This a        --  - an `a` value
| That b        --  - a `b` value
| Both a b      --  - an `a` value AND a `b` value

-- For example, These could be rewritten to
-- use a combination of Either and Tuple:
type These_ a b = Either a (Either b (Tuple a b))
``````

However, these types can also be 'open' or 'closed':

SumProductSum and Product
Closed`Either a b`

`Variant (a :: A, b :: B)`
`Tuple a b`

`Record (a :: A, b :: B)`
(e.g. `{ a :: A, b :: B }`
`These a b`
Open`Variant (a :: A | allOtherRows)``Record (a :: A | allOtherRows)`
(e.g. `{ a :: b | allOtherRows }`)
-

## What does 'Open' mean?

Using this example from the Syntax folder...

``````-- the 'r' means, 'all other fields in the record'
function :: forall r. { fst :: String, snd :: String | r } -> String
function record = record.fst <> record.snd

-- so calling the function with both record arguments below works
function { fst: "hello", snd: "world" }
function { fst: "hello", snd: "world", unrelatedField: 0 } -- works!
-- If this function used Tuple instead of Record,
--    the first argument would work, but not the second one.
``````

• `Record`s are 'nested `Tuple`s'
• `Variant`s are 'nested `Either`s'
``````-- We could write
Tuple a (Tuple b (Tuple c (Tuple d e)))
-- or we could write
{ a :: A, b :: B, c :: C, d :: D, e :: E }
-- which desugars to
Record ( a :: A, b :: B, c :: C, d :: D, e :: E )

-- We could write
Either a (Either b (Either c (Either d e)))
-- or we could write
Variant ( a :: A, b :: B, c :: C, d :: D, e :: E)
``````

Keep in mind that records/variants can be but do not necessarily have to be open. If we changed the above function's type signature to remove the `r`, it would restrict its arguments to a closed Record:

``````closed :: { fst :: String, snd :: String } -> String
closed record = record.fst <> record.snd

closed { fst: "hello", snd: "world" } -- compiles
closed { fst: "hello", snd: "world", unrelatedField: 0 } -- compiler error
``````

## The Types

### Tuple

``````data Tuple a b = Tuple a b
``````
PackageType name"Plain English" name
purescript-tuples`Tuple a b`2-value Box
UsageValues & their Usage
Stores two ordered unnamed values of the same/different types.
Can be used to return or pass in multiple unnamed values from or into a function.
`Tuple a b`

### Record

``````forall r. { a :: A, b :: B, {- ... -} | r } -- open record
{ a :: A, b :: B, {- ... -}     } -- closed record
``````
PackageType name"Plain English" name
prim`{ field :: ValueType }`an N-value Box
UsageValues & their Usage
Stores N ordered named values of the same/different types.
Can be used to return or pass in multiple unnamed values from or into a function.
`{ field :: ValueType }`

### Either

``````data Either a b
= Left a
| Right b
``````
PackageType name"Plain English" name
purescript-either`Either a b`Choice of 2 types
UsageValues & their Usage
Used to indicate one type or a second type
• `Left a` - a value of `a`
• `Right b` - a value of `b`
Error handing (when we care about the error)
• `Left a` - the error type that is returned when a computation fails
• `Right b` - the output type when a computation succeeds

## Maybe

``````data Maybe a
= Nothing
| Just a
``````

`Maybe a` is the same as `Either unimportantType a`

PackageType name"Plain English" name
purescript-maybe`Maybe a`A full or empty box
UsageValues' Representation
Indicates an optional value
• `Nothing` - value does not exist
• `Just a` - value does exist
Used for error-handling when we don't care about the error (replaces `null`)
• `Nothing` - An error occurred during computation
• `Just a` - successful computation returned output.

### Variant

This is an advanced type that will be covered in the `Hello World/Application Structure` folder.

PackageType name"Plain English" name
purescript-variant`Variant (a :: A, b :: B)`Choice of N types
UsageValues & their Usage
Used to indicate one type among many typesSee docs

### These

``````data These a b
= This a      -- Left  a
| That b      -- Right b
| Both a b    -- Tuple a b
``````
PackageType name"Plain English" name
purescript-these`These a b`Same as `Either a (Either b (Tuple a b))`

## Concluding Thoughts

Performance-wise, it's generally better to use `Record` instead of `Tuple`, and it's definitely better to use `Record` instead of a nested `Tuple`.

Similarly, it's better to use `Variant` instead of a nested `Either`. However, sometimes `Either` is all one needs and `Variant` is overkill.

For people new to the language and algebraic data types (ADTs) in general, stick with `Tuple`, `Either`, and closed `Record`s.