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 } }