[Nix-dev] with, ++, //, and laziness

Shea Levy shea at shealevy.com
Fri Mar 23 19:01:21 CET 2012


Hello,

Based on my understanding of Nix semantics, I expected the following to 
all evaluate to 2:

let
   a = { c = 1; d = b.c; };
   b = a // { c = 2; };
in b.d

let
   a = with b; { c = 1; d = c; };
   b = a // { c = 2; };
in b.d

with (throw "an error"); 2

with ({a = 2;}); with (throw "an error"); a

Unfortunately, only the first actually does. The second causes nix to 
report an infinite recursion, and the third and fourth cause nix to 
report an error as thrown. This seems to be because 'with' isn't lazy 
enough: It tries to evaluate more of its operand than is strictly 
necessary to evaluate the end result. The reason this matters is that I 
am trying to remove the use of __overrides in all-packages.nix, but in 
order to do so while maintaining the current behavior of 
packageOverrides and taking into account the infinite recursion in the 
second example above, I will have to prepend 'pkgs' to every package 
given on the RHS of an assignment in all-packages. I had hoped that I 
could add a 'with pkgs;' to the top of the packages attribute set and 
make a few other simple modifications, but alas this seems to be a 
blocker. Is there any chance of this 'with' behavior being modified? 
IMO, the semantics should be something like: if an identifier is 
referenced and it is not in scope, go up the nested 'with' chain and 
check if the operand has that identifier as an attribute. If the check 
does not evaluate to true (either because the operand doesn't have that 
identifier, the evaluator detects infinite recursion, or a 'throw' or 
'abort' is evaluated), then check up the 'with' chain until there are no 
more nested withs left. Does this make sense?

And while we're talking about making nix more lazy, could we make it so 
these terminate?

let
   f = list: number:
     let newList = [number]; in list ++ (f newList (builtins.add number 1));
in builtins.head (f [] 0)

let
   f = attrs: number:
     let
       newAttrs = builtins.listToAttrs [ { name = "a${number}"; value = 
number; } ];
     in (f newAttrs (builtins.add number 1)) // attrs;
in (f {} 0).a1

Cheers,
Shea


More information about the nix-dev mailing list