Top > Design docs > Core design > Part 05
In Sigmal, typeclasses are ordinary record types.
There is no special language-level typeclass mechanism.
Example: Functor
Functor =
\ (F : $0 -> $0)
= &{
map :
\ (A : $0)
(B : $0)
(f : A -> B)
(x : F A)
-> F B;
};
An instance is simply a record value of this type.
There is:
All dictionaries must be passed explicitly.
Applicative =
\ (F : $0 -> $0)
= &{
pure :
\ (A : $0)
(x : A)
-> F A;
ap :
\ (A : $0)
(B : $0)
(ff : F (A -> B))
(fa : F A)
-> F B;
};
Applicative is purely a structural interface.
Monad =
\ (M : $0 -> $0)
= &{
pure :
\ (A : $0)
(x : A)
-> M A;
bind :
\ (A : $0)
(B : $0)
(m : M A)
(f : A -> M B)
-> M B;
};
There is no special syntax for do-notation in the core language.
Such sugar, if provided, must desugar to explicit bind usage.
Because abstractions are ordinary records, conversion functions can be written explicitly.
Example:
monadToApplicative =
\ (M : $0 -> $0)
(mon : Monad M)
= &{
pure = mon.pure;
ap =
\ (A : $0)
(B : $0)
(ff : M (A -> B))
(fa : M A)
-> M B
= mon.bind A B fa
(\ (a : A) -> M B
= mon.bind (A -> B) B ff
(\ (f : A -> B) -> M B = mon.pure B (f a) )
);
};
No global coherence or collision issues arise because:
Sigmal does not bake effects into the language.
Effects are encoded purely via data types.
OpFrame =
\ (Op : $0 -> $0)
(A : $0)
= #{
Frame
(X : $0)
(op : Op X)
(k : X -> A);
};
This packages:
opkXFree =
\ (Op : $0 -> $0)
(A : $0)
= #{
Pure(x : A);
Op(frame : OpFrame Op (Free Op A));
};
This encodes effectful programs as pure data.
A program written in this style:
A handler is a record type; a handler value is a record value of this type:
Handler =
\ (Op : $0 -> $0)
= &{
handle :
\ (X : $0)
(op : Op X)
-> X;
};
Interpretation is explicit via a function such as:
runFree :
\ (Op : $0 -> $0)
(A : $0)
(h : Handler Op)
(p : Free Op A)
-> A;
The core language does not privilege any effect encoding.
An alternative to free constructions is capability passing.
Capabilities are explicit records:
Allocator =
&{
alloc : Nat -> Ptr;
free : Ptr -> Unit;
};
Functions requiring allocation:
makeBuffer =
\ (alloc : Allocator)
(size : Nat)
= alloc.alloc size;
There is:
All operational power must be passed explicitly.
Sigmal’s core language does not include a built-in effect system.
Effects are modeled explicitly as:
An optional future effect tracking system may:
Such a system must preserve:
If algebraic laws are required (Functor laws, Monad laws, etc.), they must be represented explicitly.
Example:
Monoid =
\ (A : $0)
= &{
empty : A;
append : A -> A -> A;
};
If associativity or identity proofs are required, they must be encoded as additional fields.
The compiler does not assume algebraic laws.
Dictionary passing is explicit.
The compiler may optimize dictionary passing (e.g., specialization or inlining), but such optimization:
All abstraction remains explicit at the language level.
Because capabilities are explicit values, Sigmal supports:
There is no ambient authority.
Abstractions in Sigmal are:
Effects are:
There is no:
All higher-level abstraction arises from:
Sigmal.org - the calculus we can build on