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