doc: Render lib.fixedPoints

+126 -88
+1
doc/default.nix
··· 11 11 { name = "strings"; description = "string manipulation functions"; } 12 12 { name = "versions"; description = "version string functions"; } 13 13 { name = "trivial"; description = "miscellaneous functions"; } 14 + { name = "fixedPoints"; baseName = "fixed-points"; description = "explicit recursion functions"; } 14 15 { name = "lists"; description = "list manipulation functions"; } 15 16 { name = "debug"; description = "debugging functions"; } 16 17 { name = "options"; description = "NixOS / nixpkgs option handling"; }
+10 -7
doc/doc-support/lib-function-docs.nix
··· 14 14 buildInputs = [ nixdoc ]; 15 15 installPhase = '' 16 16 function docgen { 17 - # TODO: wrap lib.$1 in <literal>, make nixdoc not escape it 18 - if [[ -e "../lib/$1.nix" ]]; then 19 - nixdoc -c "$1" -d "lib.$1: $2" -l ${locationsJSON} -f "$1.nix" > "$out/$1.md" 17 + name=$1 18 + baseName=$2 19 + description=$3 20 + # TODO: wrap lib.$name in <literal>, make nixdoc not escape it 21 + if [[ -e "../lib/$baseName.nix" ]]; then 22 + nixdoc -c "$name" -d "lib.$name: $description" -l ${locationsJSON} -f "$baseName.nix" > "$out/$name.md" 20 23 else 21 - nixdoc -c "$1" -d "lib.$1: $2" -l ${locationsJSON} -f "$1/default.nix" > "$out/$1.md" 24 + nixdoc -c "$name" -d "lib.$name: $description" -l ${locationsJSON} -f "$baseName/default.nix" > "$out/$name.md" 22 25 fi 23 - echo "$out/$1.md" >> "$out/index.md" 26 + echo "$out/$name.md" >> "$out/index.md" 24 27 } 25 28 26 29 mkdir -p "$out" ··· 29 32 ```{=include=} sections 30 33 EOF 31 34 32 - ${lib.concatMapStrings ({ name, description }: '' 33 - docgen ${name} ${lib.escapeShellArg description} 35 + ${lib.concatMapStrings ({ name, baseName ? name, description }: '' 36 + docgen ${name} ${baseName} ${lib.escapeShellArg description} 34 37 '') libsets} 35 38 36 39 echo '```' >> "$out/index.md"
+115 -81
lib/fixed-points.nix
··· 1 1 { lib, ... }: 2 2 rec { 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. 3 + /* 4 + Compute the fixed point of the given function `f`, which is usually an 5 + attribute set that expects its final, non-recursive representation as an 6 + argument: 7 + 8 + ``` 9 + f = self: { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; } 10 + ``` 11 + 12 + Nix evaluates this recursion until all references to `self` have been 13 + resolved. At that point, the final result is returned and `f x = x` holds: 14 + 15 + ``` 16 + nix-repl> fix f 17 + { bar = "bar"; foo = "foo"; foobar = "foobar"; } 18 + ``` 19 + 20 + Type: fix :: (a -> a) -> a 21 + 22 + See https://en.wikipedia.org/wiki/Fixed-point_combinator for further 23 + details. 24 + */ 19 25 fix = f: let x = f x; in x; 20 26 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. 27 + /* 28 + A variant of `fix` that records the original recursive attribute set in the 29 + result, in an attribute named `__unfix__`. 30 + 31 + This is useful in combination with the `extends` function to 32 + implement deep overriding. 33 + */ 25 34 fix' = f: let x = f x // { __unfix__ = f; }; in x; 26 35 27 - # Return the fixpoint that `f` converges to when called recursively, starting 28 - # with the input `x`. 29 - # 30 - # nix-repl> converge (x: x / 2) 16 31 - # 0 36 + /* 37 + Return the fixpoint that `f` converges to when called iteratively, starting 38 + with the input `x`. 39 + 40 + ``` 41 + nix-repl> converge (x: x / 2) 16 42 + 0 43 + ``` 44 + 45 + Type: (a -> a) -> a -> a 46 + */ 32 47 converge = f: x: 33 48 let 34 49 x' = f x; ··· 37 52 then x 38 53 else converge f x'; 39 54 40 - # Modify the contents of an explicitly recursive attribute set in a way that 41 - # honors `self`-references. This is accomplished with a function 42 - # 43 - # g = self: super: { foo = super.foo + " + "; } 44 - # 45 - # that has access to the unmodified input (`super`) as well as the final 46 - # non-recursive representation of the attribute set (`self`). `extends` 47 - # differs from the native `//` operator insofar as that it's applied *before* 48 - # references to `self` are resolved: 49 - # 50 - # nix-repl> fix (extends g f) 51 - # { bar = "bar"; foo = "foo + "; foobar = "foo + bar"; } 52 - # 53 - # The name of the function is inspired by object-oriented inheritance, i.e. 54 - # think of it as an infix operator `g extends f` that mimics the syntax from 55 - # Java. It may seem counter-intuitive to have the "base class" as the second 56 - # argument, but it's nice this way if several uses of `extends` are cascaded. 57 - # 58 - # To get a better understanding how `extends` turns a function with a fix 59 - # point (the package set we start with) into a new function with a different fix 60 - # point (the desired packages set) lets just see, how `extends g f` 61 - # unfolds with `g` and `f` defined above: 62 - # 63 - # extends g f = self: let super = f self; in super // g self super; 64 - # = self: let super = { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; }; in super // g self super 65 - # = self: { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; } // g self { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; } 66 - # = self: { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; } // { foo = "foo" + " + "; } 67 - # = self: { foo = "foo + "; bar = "bar"; foobar = self.foo + self.bar; } 68 - # 55 + /* 56 + Modify the contents of an explicitly recursive attribute set in a way that 57 + honors `self`-references. This is accomplished with a function 58 + 59 + ```nix 60 + g = self: super: { foo = super.foo + " + "; } 61 + ``` 62 + 63 + that has access to the unmodified input (`super`) as well as the final 64 + non-recursive representation of the attribute set (`self`). `extends` 65 + differs from the native `//` operator insofar as that it's applied *before* 66 + references to `self` are resolved: 67 + 68 + ``` 69 + nix-repl> fix (extends g f) 70 + { bar = "bar"; foo = "foo + "; foobar = "foo + bar"; } 71 + ``` 72 + 73 + The name of the function is inspired by object-oriented inheritance, i.e. 74 + think of it as an infix operator `g extends f` that mimics the syntax from 75 + Java. It may seem counter-intuitive to have the "base class" as the second 76 + argument, but it's nice this way if several uses of `extends` are cascaded. 77 + 78 + To get a better understanding how `extends` turns a function with a fix 79 + point (the package set we start with) into a new function with a different fix 80 + point (the desired packages set) lets just see, how `extends g f` 81 + unfolds with `g` and `f` defined above: 82 + 83 + ``` 84 + extends g f = self: let super = f self; in super // g self super; 85 + = self: let super = { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; }; in super // g self super 86 + = self: { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; } // g self { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; } 87 + = self: { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; } // { foo = "foo" + " + "; } 88 + = self: { foo = "foo + "; bar = "bar"; foobar = self.foo + self.bar; } 89 + ``` 90 + */ 69 91 extends = f: rattrs: self: let super = rattrs self; in super // f self super; 70 92 71 - # Compose two extending functions of the type expected by 'extends' 72 - # into one where changes made in the first are available in the 73 - # 'super' of the second 93 + /* 94 + Compose two extending functions of the type expected by 'extends' 95 + into one where changes made in the first are available in the 96 + 'super' of the second 97 + */ 74 98 composeExtensions = 75 99 f: g: final: prev: 76 100 let fApplied = f final prev; 77 101 prev' = prev // fApplied; 78 102 in fApplied // g final prev'; 79 103 80 - # Compose several extending functions of the type expected by 'extends' into 81 - # one where changes made in preceding functions are made available to 82 - # subsequent ones. 83 - # 84 - # composeManyExtensions : [packageSet -> packageSet -> packageSet] -> packageSet -> packageSet -> packageSet 85 - # ^final ^prev ^overrides ^final ^prev ^overrides 104 + /* 105 + Compose several extending functions of the type expected by 'extends' into 106 + one where changes made in preceding functions are made available to 107 + subsequent ones. 108 + 109 + ``` 110 + composeManyExtensions : [packageSet -> packageSet -> packageSet] -> packageSet -> packageSet -> packageSet 111 + ^final ^prev ^overrides ^final ^prev ^overrides 112 + ``` 113 + */ 86 114 composeManyExtensions = 87 115 lib.foldr (x: y: composeExtensions x y) (final: prev: {}); 88 116 89 - # Create an overridable, recursive attribute set. For example: 90 - # 91 - # nix-repl> obj = makeExtensible (self: { }) 92 - # 93 - # nix-repl> obj 94 - # { __unfix__ = «lambda»; extend = «lambda»; } 95 - # 96 - # nix-repl> obj = obj.extend (self: super: { foo = "foo"; }) 97 - # 98 - # nix-repl> obj 99 - # { __unfix__ = «lambda»; extend = «lambda»; foo = "foo"; } 100 - # 101 - # nix-repl> obj = obj.extend (self: super: { foo = super.foo + " + "; bar = "bar"; foobar = self.foo + self.bar; }) 102 - # 103 - # nix-repl> obj 104 - # { __unfix__ = «lambda»; bar = "bar"; extend = «lambda»; foo = "foo + "; foobar = "foo + bar"; } 117 + /* 118 + Create an overridable, recursive attribute set. For example: 119 + 120 + ``` 121 + nix-repl> obj = makeExtensible (self: { }) 122 + 123 + nix-repl> obj 124 + { __unfix__ = «lambda»; extend = «lambda»; } 125 + 126 + nix-repl> obj = obj.extend (self: super: { foo = "foo"; }) 127 + 128 + nix-repl> obj 129 + { __unfix__ = «lambda»; extend = «lambda»; foo = "foo"; } 130 + 131 + nix-repl> obj = obj.extend (self: super: { foo = super.foo + " + "; bar = "bar"; foobar = self.foo + self.bar; }) 132 + 133 + nix-repl> obj 134 + { __unfix__ = «lambda»; bar = "bar"; extend = «lambda»; foo = "foo + "; foobar = "foo + bar"; } 135 + ``` 136 + */ 105 137 makeExtensible = makeExtensibleWithCustomName "extend"; 106 138 107 - # Same as `makeExtensible` but the name of the extending attribute is 108 - # customized. 139 + /* 140 + Same as `makeExtensible` but the name of the extending attribute is 141 + customized. 142 + */ 109 143 makeExtensibleWithCustomName = extenderName: rattrs: 110 144 fix' (self: (rattrs self) // { 111 145 ${extenderName} = f: makeExtensibleWithCustomName extenderName (extends f rattrs);