Many definitions, classes, and enums are only useful on a specific set of data. Occasionally, an algorithm or data type is useful for any kind of data type.
A simple generic function can be written as follows:
define interpolate[A](value: A): String
{
return value ++ ""
}
print(interpolate(1)) # 1
print(interpolate([1, 2, 3])) # [1, 2, 3]
print(interpolate) # <function interpolate>
Generics start at A
and work up to Z
. It is currently not possible to have
custom names for generics. A more complex generic function can be written as
follows.
define transform[A, B](value: A, fn: Function(A => B)): B
{
return fn(value)
}
print(transform([1, 2, 3], List.size)) # 3
Classes are also able to make use of generics. Generics in class methods start after class generics.
class Container[A]
{
public var @values: List[A] = []
public define send(v: A): self
{
@values.push(v)
}
public define apply[B](f: Function(A => B)): List[B]
{
var result: List[B] = []
for i in 0...@values.size() - 1: {
@values[i]
|> f
|> result.push
}
return result
}
}
var v = Container()
.@(Container[String])
.send("1")
.send("100")
.send("1b")
.send("5000")
.send("a")
.apply(String.parse_i)
.select(Option.is_some)
.map(Option.unwrap)
.fold(0, (|a, b| a + b ))
print(v) # 5101
Enums and their variants also support generics.
enum Tree[A]
{
Branch(Tree[A]...),
Leaf(A)
define all: List[A]
{
var result_list: List[A] = []
var source_list: List[Tree[A]] = [self]
while source_list.size(): {
var s = source_list.pop()
match s: {
case Leaf(result):
result_list.push(result)
case Branch(target_list):
source_list = source_list.merge(target_list)
}
}
return result_list
}
}
var v =
Branch(
Branch(
Leaf(1),
Leaf(20)
),
Leaf(300),
Branch(
Leaf(4000),
Leaf(50000)
)
)
.all()
.fold(0, (|a, b| a + b ))
print(v) # 54321