hnix/README-design.md

44 lines
2.2 KiB
Markdown

# Design of the hnix code base
Welcome to the hnix code! You may notice some strange things as you venture
into this realm, so this document is meant to prepare you, dear reader, for
the secrets of the labyrinth as we've designed them.
The first thing to note is that hnix was primarily designed so that Haskell
authors could use it to craft custom tooling around the Nix ecosystem. Thus,
it was never fully intended for just the end user. As a result, we use a great
deal of abstraction so that these enterprising Haskell authors may inject
their own behavior at various points within the type hierarchy, the value
representation, and the behavior of the evaluator.
To this end, you'll see a lot of type variables floating around, almost
everywhere. These provide many of the "injection points" mentioned above.
There is a strict convention followed for the naming of these variables, the
lexicon for which is stated here.
`t` is the type of thunks. It turns out that hnix dosen't actually need to
know how thunks are represented, at all. It only needs to know that the
interface can be honored: pending action that yield values may be turned into
thunks, and thunks can later be forced into values.
`f` is the type of a comonadic and applicative functor that gets injected at
every level of a value's recursive structure. In the standard evaluation
scheme, this is used to provide "provenance" information to track which
expression context a value originated from (e.g., this 10 came from that
expression "5 + 5" over in this file, here).
`m` is the "monad of evaluation", which must support at least the features
required by the evaluator. The fact that the user can evaluate in his own base
monad makes it possible to create custom builtins that make use of arbitrary
effects.
`v` is the type of values, which is almost always going to be `NValue t f m`,
though it could be `NValueNF t f m`, the type of normal form values. Very few
points in the code are generic over both.
## Different value types
Having said that, I should mention that there are two different types of
values: `NValue` and `NValueNF`. The former is created by evaluating an
`NExpr`, and then latter by calling `normalForm` on an `NValue`.