at 17.09-beta 3.2 kB view raw
1rec { 2 # Compute the fixed point of the given function `f`, which is usually an 3 # attribute set that expects its final, non-recursive representation as an 4 # argument: 5 # 6 # f = self: { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; } 7 # 8 # Nix evaluates this recursion until all references to `self` have been 9 # resolved. At that point, the final result is returned and `f x = x` holds: 10 # 11 # nix-repl> fix f 12 # { bar = "bar"; foo = "foo"; foobar = "foobar"; } 13 # 14 # Type: fix :: (a -> a) -> a 15 # 16 # See https://en.wikipedia.org/wiki/Fixed-point_combinator for further 17 # details. 18 fix = f: let x = f x; in x; 19 20 # A variant of `fix` that records the original recursive attribute set in the 21 # result. This is useful in combination with the `extends` function to 22 # implement deep overriding. See pkgs/development/haskell-modules/default.nix 23 # for a concrete example. 24 fix' = f: let x = f x // { __unfix__ = f; }; in x; 25 26 # Modify the contents of an explicitly recursive attribute set in a way that 27 # honors `self`-references. This is accomplished with a function 28 # 29 # g = self: super: { foo = super.foo + " + "; } 30 # 31 # that has access to the unmodified input (`super`) as well as the final 32 # non-recursive representation of the attribute set (`self`). `extends` 33 # differs from the native `//` operator insofar as that it's applied *before* 34 # references to `self` are resolved: 35 # 36 # nix-repl> fix (extends g f) 37 # { bar = "bar"; foo = "foo + "; foobar = "foo + bar"; } 38 # 39 # The name of the function is inspired by object-oriented inheritance, i.e. 40 # think of it as an infix operator `g extends f` that mimics the syntax from 41 # Java. It may seem counter-intuitive to have the "base class" as the second 42 # argument, but it's nice this way if several uses of `extends` are cascaded. 43 extends = f: rattrs: self: let super = rattrs self; in super // f self super; 44 45 # Compose two extending functions of the type expected by 'extends' 46 # into one where changes made in the first are available in the 47 # 'super' of the second 48 composeExtensions = 49 f: g: self: super: 50 let fApplied = f self super; 51 super' = super // fApplied; 52 in fApplied // g self super'; 53 54 # Create an overridable, recursive attribute set. For example: 55 # 56 # nix-repl> obj = makeExtensible (self: { }) 57 # 58 # nix-repl> obj 59 # { __unfix__ = «lambda»; extend = «lambda»; } 60 # 61 # nix-repl> obj = obj.extend (self: super: { foo = "foo"; }) 62 # 63 # nix-repl> obj 64 # { __unfix__ = «lambda»; extend = «lambda»; foo = "foo"; } 65 # 66 # nix-repl> obj = obj.extend (self: super: { foo = super.foo + " + "; bar = "bar"; foobar = self.foo + self.bar; }) 67 # 68 # nix-repl> obj 69 # { __unfix__ = «lambda»; bar = "bar"; extend = «lambda»; foo = "foo + "; foobar = "foo + bar"; } 70 makeExtensible = makeExtensibleWithCustomName "extend"; 71 72 # Same as `makeExtensible` but the name of the extending attribute is 73 # customized. 74 makeExtensibleWithCustomName = extenderName: rattrs: 75 fix' rattrs // { 76 ${extenderName} = f: makeExtensibleWithCustomName extenderName (extends f rattrs); 77 }; 78}