Traits
Traits are a way to describe the “behavior” of one or more types. For example, the Show
trait defines what the show
function should display for a value of a given type. To define a trait, use the trait
template in conjunction with a type function:
Default : A => trait A
Here, Default
is a trait that defines the “default value” for a type.
We can implement a trait for a specific type using an instance
pattern:
instance (Default Number) : 0
instance (Default Text) : ""
instance (Default Boolean) : False
-- ...and so on
To use a specfic implementation of a trait, refer to the trait by its name. The implementation used depends on the type of the surrounding expression:
a : (Default :: Number) -- a : 0
b : (Default :: Text) -- b : ""
c : (Default :: Boolean) -- c : False
You can also store more complicated values inside the trait’s implementation, eg. a function:
Equal : A => trait (A -> A -> Boolean)
Person : type {
name :: Text
age :: Number
}
instance (Equal Person) -> p1 -> p2 ->
name of p1 = name of p2
and age of p1 = age of p2
alice : Person {
name : "Alice"
age : 25
}
bob : Person {
name : "Bob"
age : 30
}
Equal alice bob -- False
Equal bob bob -- True
And you can use generics in instance
declarations by providing a type function:
-- The "default" value of a list is the empty list
A => instance (Default (List A)) : (list)
Bounded constants and instances
You can use a where
clause in a type function to provide bounds on the type parameters. For example:
show :: A where (Show A) => A -> ()
A B C where (Default A) (Default B) (Default C) =>
instance (Default (A , B , C)) : Default , Default , Default