Generics
Khora supports type parameters, trait bounds, const parameters, row variables, higher-kinded use, explicit forall, and variance annotations.
Type parameters on functions
Section titled “Type parameters on functions”fn identity<A>(value: A) -> A { value}Several parameters:
fn pair<A, B>(left: A, right: B) -> (A, B) { (left, right)}General parameter-list shape:
<Name, Name, ...>Type parameters on data types
Section titled “Type parameters on data types”pub type Box<A> = { value: A,};
pub type Result<A, E> = | Ok(value: A) | Err(error: E);Generic type arguments
Section titled “Generic type arguments”Box<Int>Result<User, DbError>Map<String, User><...> in type position is always a type-argument list; no turbofish syntax is required.
Trait bounds
Section titled “Trait bounds”Single bound:
fn same<A: Eq>(left: A, right: A) -> Bool { left == right}Several bounds:
fn render<A: Eq + Show>(value: A) -> String { value.show()}General form:
A: Trait + OtherTraitEach bound is a trait path. Ask for the smallest useful one: a function that
needs only equality should bound on Eq and not on something broader, because
the bound is what a caller has to satisfy.
Const generic parameters
Section titled “Const generic parameters”pub type Matrix<A, const Rows: Int, const Cols: Int>;General form:
const Name: TypeInteger literals can be supplied as type arguments:
Matrix<Float, 4, 4>Embedding<1536>A const generic is part of a type’s compile-time identity; it is distinct from a module-level const declaration.
Row-variable parameters
Section titled “Row-variable parameters”fn call<A, B, 'ef, 'er>( value: A, f: A -> B with 'ef raises 'er,) -> B with 'ef raises 'er{ f(value)!}A row variable is introduced directly in the generic parameter list:
'ef'erIts spelling is arbitrary; the position where it is used determines whether it represents capability requirements, failures, or another row-shaped type.
This is why an effectful or fallible function can be handed to an ordinary
higher-order operation without a separate traverse-shaped API beside it: the
combinator is polymorphic in the rows its argument carries, and passes them
through to its own signature.
Open record/capability rows
Section titled “Open record/capability rows”{ db: Db | 'ef }The named entries are required and the row variable represents any additional entries.
Higher-kinded use
Section titled “Higher-kinded use”A generic parameter can be used as a type constructor when its use requires that kind:
fn construct<F, A>(value: A, make: A -> F<A>) -> F<A> { make(value)}Here F is used with one type argument, so it is a type constructor rather than an inhabited concrete type. Kinds are checked from how parameters are used; Khora does not require a separate source-level kind annotation on this declaration.
Explicit forall
Section titled “Explicit forall”A type value can quantify its own parameters:
forall<A>. A -> ASeveral parameters:
forall<A, B>. (A, B) -> (B, A)Const parameter:
forall<A, const N: Int>. A -> Vector<A>General form:
forall<TypeParams>. TypeNamed generic declarations introduce their parameters directly and usually do
not need explicit forall. It earns its place in an API that stores or accepts
a polymorphic function value, where there is no declaration to hang the
parameter on.
Variance annotations
Section titled “Variance annotations”Covariant parameter:
pub type Source<+A>;Contravariant parameter:
pub type Sink<-A>;Invariant parameter:
pub type Cell<A>;General forms:
+A-AAVariance is written on the parameter declaration itself. Reach for it when designing a reusable abstraction whose subtype relationship depends on the parameter; an ordinary data type normally leaves it unmarked.
Generic implementations
Section titled “Generic implementations”impl<A: Show> Show for Box<A> { fn show(self) -> String { self.value.show() }}Type parameters immediately after impl are in scope for the implemented trait, target type, associated types, and methods in that block.
Generic effects and traits
Section titled “Generic effects and traits”Effects and traits may also take type parameters:
pub effect Cache<K, V> { get: K -> Option<V>,}
pub trait Convert<A> { fn convert(self) -> A;}The parameter grammar is shared across functions, types, traits, effects, and implementation blocks.
See Traits for associated types and implementations and Types for function types, rows, and forall in context.
Khora 0.1.0built frombd964738afb6on 2026-10-17 20:41ZVersioningSecurityContributingReleasesSource