Noogλe
Function of the day
fix fcomputes the fixed point of the given functionf. In other words, the return value isxinx = f x.fmust be a lazy function. This means thatxmust be a value that can be partially evaluated, such as an attribute set, a list, or a function. This way,fcan use one part ofxto compute another part.Relation to syntactic recursion
This section explains
fixby refactoring from syntactic recursion to a call offixinstead.For context, Nix lets you define attributes in terms of other attributes syntactically using the
rec { }syntax.nix-repl> rec { foo = "foo"; bar = "bar"; foobar = foo + bar; } { bar = "bar"; foo = "foo"; foobar = "foobar"; }This is convenient when constructing a value to pass to a function for example, but an equivalent effect can be achieved with the
letbinding syntax:nix-repl> let self = { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; }; in self { bar = "bar"; foo = "foo"; foobar = "foobar"; }But in general you can get more reuse out of
letbindings by refactoring them to a function.nix-repl> f = self: { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; }This is where
fixcomes in, it contains the syntactic recursion that's not infanymore.nix-repl> fix = f: let self = f self; in self;By applying
fixwe get the final result.nix-repl> fix f { bar = "bar"; foo = "foo"; foobar = "foobar"; }Such a refactored
fusingfixis not useful by itself. Seeextendsfor an example use case. Thereselfis also often calledfinal.Inputs
f-
1. Function argument
Type
fix :: (a -> a) -> aExamples
lib.fixedPoints.fixusage examplefix (self: { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; }) => { bar = "bar"; foo = "foo"; foobar = "foobar"; } fix (self: [ 1 2 (elemAt self 0 + elemAt self 1) ]) => [ 1 2 3 ]