Appearance
Classes
Classes are AIVI's typeclass-style abstraction mechanism. A class describes a set of operations that a type must provide. For the canonical executable support reference for higher-kinded classes, current builtin/runtime-backed carriers, the builtin-vs-authored execution boundary, and user-authored instance limits, see Typeclasses & Higher-Kinded Support. For the semantic contract behind those instances, see Class Laws & Design Boundaries.
Declaring a class
aivi
class Eq AThis says that any type used with Eq must support equality.
You can declare ordinary named methods too:
aivi
class Display ABlock body syntax
When a class has multiple members, group them inside = { ... }:
aivi
class Eq A = {
type (==) : A -> A -> Bool
}
class Display A = {
type display : A -> Text
type label : A -> Text
}Instance declarations use the same block form:
aivi
instance Eq Blob = {
(==) = left right => blobEquals left right
}Superclass declarations
Use with inside the class body to declare that your class extends another class. Any instance of the derived class must also provide an instance of each superclass.
aivi
class Named A
class Displayed A
class Logged A = {
with Named A
with Displayed A
}Multiple superclasses are listed as separate with lines.
aivi
class CacheKey A = {
with Eq A
with Hashable A
}Parameter constraints
Use require inside the class body to constrain a type parameter. This documents that any type substituted for that parameter must satisfy the given class.
aivi
class Container A = {
require Eq A
}Using class-backed operators
When a type already has an instance, you can use the operator directly:
aivi
type Int -> Int -> Bool
func equivalent = left right =>
left == right and left != 0
value sameNumber = equivalent 4 4Surface != uses the same Eq evidence as ==, so once equality exists both operators become available at use sites.
Ord uses compare : A -> A -> Ordering as its primitive member. Surface ordering operators are derived from that member, so <, >, <=, and >= all work once an Ord instance exists.
Declaring an instance
Instances provide the implementation for a concrete type:
aivi
class Eq A
type Blob = Blob Bytes
type Blob -> Blob -> Bool
func blobEquals = left right =>
True
instance Eq BlobNamed class methods
A class can expose named operations instead of operators:
aivi
class Compare A
type Label = Label Text
instance Compare LabelEq constraints on functions
When a function needs to compare values of an open type parameter, use a constraint prefix on the annotation:
aivi
type Eq K => K -> K -> Bool
func matchesKey = key candidate =>
key == candidateMultiple constraints use a parenthesized comma-separated list:
aivi
type (Eq A, Eq B) => A -> A -> B -> B -> Bool
func bothEqual = leftA rightA leftB rightB =>
leftA == rightA and leftB == rightBThe constraint ensures the function can only be called when K (or A, B, etc.) has an Eq instance. Without the constraint, using == on an open type parameter is a type error.
Ord constraints and domain ordering
Use Ord when a function needs ordering rather than just equality:
aivi
type Ord A => A -> A -> Bool
func nonDecreasing = left right =>
left <= rightFor nominal domains, implement compare in the Ord instance and then use the ordinary operators:
aivi
domain Calendar over Int = {
suffix day
type day : Int
day = value => Calendar value
type toDays : Calendar -> Int
}
instance Ord Calendar = {
compare = left right => compare (toDays left) (toDays right)
}
value ordered : Bool = 10day < 12day
value distinct : Bool = 10day != 12dayYou normally explain equality once and let surface != reuse that same evidence. You also do not need to author separate class or domain members for <, >, <=, or >=; those surface operators are sugar over Ord.compare.
Why classes matter
Classes let generic code talk about capability instead of one hard-coded type. They are useful when you want a common interface for comparison, display, accumulation, or traversal.
Summary
| Form | Meaning |
|---|---|
class Eq A | Declare a class with a type parameter |
(==) : A -> A -> Bool | Require an operator |
display : A -> Text | Require a named method |
with Functor F | Declare a superclass in the class body |
require Eq A | Constrain a class type parameter |
instance Eq Blob | Implement a class for one concrete type |
type Eq K => K -> K -> Bool | Require K to have Eq in a function annotation |
class Name A = { ... } | Group class members in a block |
See also: Typeclasses & Higher-Kinded Support — canonical executable support reference, builtin-vs-authored execution boundary, HKT hierarchy, and user-authored instance limits; Class Laws & Design Boundaries — the semantic contract behind lawful instances