Are there generators in the nix language?

Does the nix language have generators, or anything similar?

Rather often, I find myself hardcoding values in sequence (e.g. for MAC addresses for network devices, or port numbers services should listen to), and I would find it useful to be able to write a next_value function that would return a new valid value.

If there is no such constructs, are there patterns that you folks are using to avoid keeping track of the attributed values throughout your code?

I don’t know if having generators in a lazy language make sense… But I may be wrong.

The problem you are having it is the one of state.

A generator in a lazy language would require something akin to a monadic context to hide the state in there, otherwise you would have to write code like:

    initialValue = 0;
    v1 = gen initialValue;
    v2 = gen v1;
    v3 = gen v2;
    # ... as much as needed
f v1 + f v2 + f v3

or something.

In a monadic context, you could have:

   monadicGenerator = createGenerator (oldValue: oldValue + 1) 0;
f (monadicGenerator ()) + f (monadicGenerator ()) + f (monadicGenerator ())

But that’s not a thing.


Well, technically monads are not an essential thing in a language - it is possible to create a library for them instead of requiring modifications in the interpreter.

But this is a thing only a Lisp hacker would think :upside_down_face:


Slightly off-topic, but related question about implementing generator / state.

@RaitoBezarius @AndersonTorres, could you help with an issue regarding implementing a part of the Mustache spec in Nix?

Is it feasible to implement something in Nix simpilar to Closure (def g (atom 0)) (fn [] (swap! g inc)) or Lisp (let ((g 0)) (lambda () (incf g))) ?

You can encode state in a pure functional language, but that encoding transforms lambdas. You’d represent the hypothetical mutable-Nix expression let mutable s = 0; in _: s++ as something like _: s: { result = s; nextState = s + 1; }, and you’d make the appropriate transformations to the rest of the program as well. There’s no way to use a pure lambda as-is, with no extra arguments or return values, to represent a mutable cell.

All the fuss about monads is just a common interface over such encodings. It doesn’t make the encodings go away, which is why when working with functions that return monadic types in Haskell you have to use >>= or do-notation to work with the contained value instead of directly using their results.