Skip to content

Latest commit

 

History

History
68 lines (48 loc) · 2.32 KB

4. Tagged Unions.md

File metadata and controls

68 lines (48 loc) · 2.32 KB

Tagged Unions

Headpats allow you to make tagged unions, also known as discriminated unions or sum types.
Then, you can pattern match these values like other types.

Creation

  • union(name, ...types)

The pat.union function creates a new class representing the tagged union.
The name is the name of the union, and its used to correctly name the class.
The types are the types in the union and can either be a string representing the name, or a [string, kind] pair.
The kind would be one of 'value' or 'array', and if not provided, defaults to 'value'.

The function returns a class for the tagged union which contains the types.
Each type can be instantiated as they are just classes.
A type with the 'value' kind will only take in one argument, while the 'array' kind can take in any.
The class has one property, value for the value(s) passed in.

const Union = pat.union('Union', 'Value', ['AlsoValue', 'value'], ['Things', 'array']);
const { Value, AlsoValue, Things } = Union;

new Value(1)
 Value { value: 1 }

new AlsoValue(2, 3, 4)
 AlsoValue { value: 2 }

new Things(2, 3, 4)
 Things { value: [2, 3, 4] }

Types with the 'value' kind are for single-valued types, while the 'array' kind can be used to simulate tuples.

Pattern Matching

While values from tagged unions can be matched with the InstancePattern, there is also TagPattern.
They both check if the value extends some class, but the difference is that TagPattern will use the value property of the instance instead of the instance itself.
The TagPattern is also available as is.tag and as a case of $$ (see here for specifics).

const { Some, None } = pat.union('Option', 'Some', 'None');

const unwrap = pat
    .case($$(Some, $.x), ({ x }) => x)
    .case($$(None, _), () => {
        throw new TypeError('Cannot unwrap None');
    });

unwrap(new Some(10))
 10

unwrap(new None())
 Error

In order to get the original wrapped value instead of the value inside, you would use the bind pattern or the instance pattern.

const { Some, None } = pat.union('Option', 'Some', 'None');

pat.match(is.bind($$(Some, $.x), 's'), new Some(5))
 { x: 5, s: Some { value: 5 } }

pat.match(is.instance(Some, $.x), new Some(5))
 { x: Some { value: 5 } }