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}