A tiny & fast composable type system for Nix, in Nix.
Named after the little penguin.
- Types
- Primitive types (
string,int, etc) - Polymorphic types (
union,attrsOf, etc) - Struct types
- Primitive types (
- Verification
Basic verification is done with the type function verify:
{ korora }:
let
t = korora.string;
value = 1;
# Error contains the string "Expected type 'string' but value '1' is of type 'int'"
error = t.verify 1;
in if error != null then throw error else valueErrors are returned as a string.
On success null is returned.
- Checking (assertions)
For convenience you can also check a value on-the-fly:
{ korora }:
let
t = korora.string;
value = 1;
# Same error as previous example, but `check` throws.
value = t.check value value;
in valueOn error check throws. On success it returns the value that was passed in.
For usage example see tests.nix.
Declare a custom type using a bool function
name
: Name of the type as a string
verify
: Verification function returning a bool.
Declare a custom type using an option function.
name
: Name of the type as a string
verify
: Verification function returning null on success & a string with error message on error.
String
Type alias for string
Any
Never
Int
Single precision floating point
Either an int or a float
Bool
Attribute with undefined attribute types
Attribute with undefined element types
Function
Path
Derivation
Type
Option
t
: Null or t
listOf
t
: Element type
listOf
t
: Attribute value type
union<types...>
types
: Any of
intersection<types...>
types
: All of
rename<name, type>
Because some polymorphic types such as attrsOf inherits names from it's sub-types we need to erase the name to not cause infinite recursion.
myType = types.attrsOf (
types.rename "eitherType" (types.union [
types.string
myType
])
);name
: Function argument
type
: Function argument
struct<name, members...>
korora.struct "myStruct" {
foo = types.string;
}- Totality
By default, all attribute names must be present in a struct. It is possible to override this by specifying totality. Here is how to do this:
(korora.struct "myStruct" {
foo = types.string;
}).override { total = false; }This means that a myStruct struct can have any of the keys omitted. Thus these are valid:
let
s1 = { };
s2 = { foo = "bar"; }
in ...- Unknown attribute names
By default, unknown attribute names are allowed.
It is possible to override this by specifying unknown.
(korora.struct "myStruct" {
foo = types.string;
}).override { unknown = false; }This means that
{
foo = "bar";
baz = "hello";
}is normally valid, but not when unknown is set to false.
Because Nix lacks primitive operations to iterate over attribute sets dynamically without allocation this function allocates one intermediate attribute set per struct verification.
- Custom invariants
Custom struct verification functions can be added as such:
(types.struct "testStruct2" {
x = types.int;
y = types.int;
}).override {
verify = v: if v.x + v.y == 2 then "VERBOTEN" else null;
};name
: Name of struct type as a string
members
: Attribute set of type definitions.
optionalAttr
t
: Function argument
enum<name, elems...>
name
: Name of enum type as a string
elems
: List of allowable enum members
defun<name, args, returns, function>
let
wrappedFunc = types.defun "fn" [ types.str ] types.str (s: s + "-checked");
in
# Returns "foo-checked"
wrappedfunc "foo"