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?
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:
let
initialValue = 0;
v1 = gen initialValue;
v2 = gen v1;
v3 = gen v2;
# ... as much as needed
in
f v1 + f v2 + f v3
or something.
In a monadic context, you could have:
let
monadicGenerator = createGenerator (oldValue: oldValue + 1) 0;
in
f (monadicGenerator ()) + f (monadicGenerator ()) + f (monadicGenerator ())
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
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.