Polymorphism
LIGO supports simple polymorphism when introducing declarations. This allows to write functions parametric on a type that can be later instantiated to concrete types.
The identity function
For any given type t
, there is a canonical function of type t -> t
(function from t
to t
): it takes an argument, and returns it
immediately. For instance, we can write the identity function for
int
as follows:
However, if we would want to use the same function on a different
type, such as nat
, we will need to write a new definition:
If we read carefully, we see that there is almost no difference
between id
and idnat
: it is just the type that changes, but for
the rest, the body of the function remains the same.
Thanks to parametric polymorphism, we can write a single function declaration that works for both cases.
Here T
is a type variable which can be generalised. In general,
types prefixed with _
are treated as generalisable.
We can then use this function directly in different types by just regular application:
During compilation, LIGO will monomorphise the polymorphic functions into specific instances, resulting in Michelson code that does not contain polymorphic function declarations anymore.
Polymorphism with parametric types
Polymorphism is especially useful when writing functions over parametric types, which include built-in types like lists, sets, and maps.
As an example, we will see how to implement list reversing parametrically on any type, rather than just on lists of a specific type.
Similar to the id
example, we can introduce a type variable that can
be generalised. We will write a direct version of the function using
an accumulator, but the reader can experiment with different
variations by using List
combinators.
We use an accumulator variable acc
to keep the elements of the list
processed, consing each element on it. As with the identity function,
we can then use it directly in different types: