2019-03-16 19:41:48 +01:00
|
|
|
# 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.
|
2019-03-17 07:13:13 +01:00
|
|
|
|
|
|
|
## 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`.
|