Generics

Wipple has a powerful type system that lets you express relationships between values. Often, you’ll want to implement a function or instance that works for any input type — for example, implementing Equal for Maybe Value where Equal Value is implemented.

Wipple lets you express generics using type functions, which use the => operator. The left-hand side of the type function introduces type parameters into scope, and the right-hand side is a type depending on these parameters. For example, we can define Maybe as follows:

Maybe : Value => type {
    Some Value
    None
}

Type functions can also be used with traits, constants and instances:

Show : A => trait (A -> Text)

unwrap :: A => Maybe A -> A
unwrap : ...

A where (Show A) => instance (Show (Maybe A)) : ...

That where clause in the above example allows you to introduce bounds on the type parameters — that is, the type, trait, constant or instance may only be used if there are instances matching the trait with the provided parameters.

You can provide as many parameters and bounds as you want:

A B C where (T A) (U B) (V C) => ...

Unused type parameters

In a type declaration, you don’t need to actually use the parameters anywhere in the type. This is useful for creating “type states” that represent data at the type level:

Idle : type
Hovering : type

Drone : State => type

take-off :: Drone Idle -> Drone Hovering
take-off : just Drone

land :: Drone Hovering -> Drone Idle
land : just Drone


my-drone :: Drone Idle
my-drone : Drone

my-drone . take-off . land -- works!
my-drone . land -- cannot land because drone is already idle

Implicit type parameters

In constants, instance definitions, and where bounds, you can replace a type parameter with a type placeholder (_). There, _ indicates an implicit type parameter. For example, Element is only used once in the signature of count, so you can replace it with a type placeholder:

-- explicit type parameter
count :: Collection Element where (Iterate Collection Element) => Collection -> Natural

-- implicit type parameter
count :: Collection where (Iterate Collection _) => Collection -> Natural

Note that you cannot use implicit type parameters in type or trait definitions, because that would prevent you from calling their type functions.