Skip to content

Instantly share code, notes, and snippets.

@thufschmitt
Created August 5, 2023 15:20
Show Gist options
  • Save thufschmitt/c3a89306f87185b061c3e7d06dcfa4dd to your computer and use it in GitHub Desktop.
Save thufschmitt/c3a89306f87185b061c3e7d06dcfa4dd to your computer and use it in GitHub Desktop.
Modules for Nickel
# A library for NixOS-style “modules”
#
# Modules are records whose contract gets extended through merging: `Module c`
# is a contract semantically equivalent to `c`, except that if `foo` has
# contract `Module x` and `bar` has contract `Module y`, then `foo & bar` will
# have contract `Module (x&y)`.
{
empty = { contract.contract | optional },
Module
| doc m%"
Define a module contract
# Example
```nickel
{ foo = 1, bar = 2 } | Module { foo | Number, bar | Number }
```
"%
= fun module_contract label value =>
(value & { contract = module_contract }),
ValidModule
| doc m%"
Extensible records which define their own contract.
The contract for a record is defined by its `contract` field.
This allows modules to have a contract that's both closed and extensible by
merging (by extending the `contract` field).
# Examples
```nickel
let m1 = { contract.foo | Number, foo = 1 } in
let m2 = { contract.bar | String, bar = "bar" } in
(m1 & m2) | ValidModule
"%
= fun label value =>
let with_ensured_contract = value & empty in
std.contract.apply
with_ensured_contract.contract
label
with_ensured_contract,
SubModule = fun label value => std.contract.apply ValidModule label value |> fix,
fix | ValidModule -> Dyn
# | std.contract.unstable.DependentFun ValidModule (fun x => std.record.remove "contract" x.contract)
= fun module => std.record.remove "contract" (module & { contract | force = null }),
test.simple = fix ({ foo = 1 } | Module { foo | Number }),
test."merge" =
let m1 | Module { foo | Number } = { foo = 1 } in
let m2 | Module { bar | String } = { bar = "blah" } in
fix (m1 & m2),
test.sub =
let sub | Module { y | Number, z | Number | default = y+1 } = {} in
fix
(
{
foo.x = sub & { y = 1 },
foo.z = sub & { y = 1 },
foo.z.z = 3,
} | Module {
foo | {_: SubModule}
}
),
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment