Templates
Declaring templates
To write a function that works for many different types, you would use a template.
To make a declaration a template, write []
after the name,
with type parameter names listed inside, as in any[t]
.
(The []
have a different meaning on a declaration than they do for a map type v[k]
).
any
is technically a function template and not a function.
It is instantiated into two different functions.
The first (nats any x => x is-even
) calls an instantiation
of any
where t
is replaced by nat
.
The second call (strings any x => x == "pi"
) uses string
instead.
Explicit type arguments
In the above example, Crow infers how to instantiate any
based on the first argument.
(It gets a nat[]
and needs a t[]
, so t
must be nat
.)
You should almost always rely on inference. But when you do get a compile error,
you can often get a better error by specifying what the type arguments should be.
The syntax for this looks like any@nat
.
When the template takes multiple types or the type argument is a complex type,
write it with parentheses, like combinations@(nat, string)
.
Templated types
Just like there are function templates, there are type templates.
The syntax to instantiate a type template looks like nat by-name
,
where nat
is the type argument and by-name
is the template.
If there were multiple type arguments, this would look like (nat, bool) by-name
.
Type templates can be chained without parentheses. Each suffix applies from left to right.
nat?[]
is a list
of
option
al nat
s,
while nat[]?
is an option
al
list
of nat
s.
The purity of type arguments affects the purity of the type.
So even though list
is data
,
string-builder[]
is mut
because
string-builder
is.
Templates are safe
Templated functions are type-checked as templates, meaning before they are instantiated.
That means that expressions in a template must work for all possible types.
This avoids confusing compile errors where a template only fails to compile in certain instantiations. But, it does require additional work to write templates that rely on certain operations existing.
We'll see how to make this work in Specs.