Please, explain like I am 5 years old how that `finalAttrs: {}`

design pattern works in tandem with `stdenv.mkDerivation`

.

And, possibly, how can it be adapted to work with other frameworks (like, say, `buildGoModule`

).

I was playing with nix repl:

```
> fun = finalAttrs: { a=1; b = finalAttrs.a+1; c = finalAttrs.b+2; }
> fun { a=0; }
nix-repl> fun ( { a = 0; })
{ a = 1; b = 1; c = error: attribute 'b' missing
at «string»:1:45:
1| finalAttrs: { a=1; b = finalAttrs.a+1; c = finalAttrs.b+2; }
| ^
Did you mean a?
nix-repl> fun (fun { a = 0; })
{ a = 1; b = 2; c = 3; }
nix-repl>
```

However it didn’t help me too much.

2 Likes

It’s more like this:

```
> fun = finalAttrs: { a=1; b = finalAttrs.a+1; c = finalAttrs.b+2; }
> fix = f: let x = f x; in x
> fix fun
{ a = 1; b = 2; c = 4; }
```

The magic is that `fix`

function. It calls a function with its own result as the argument (that’s what `let x = f x`

does). This is possible because of laziness. So `fun`

returns `{ a = 1;, b = <thunk>; c = <thunk>; }`

. If you evaluate `b`

, then it’ll evaluate `finalAttrs.a + 1`

, which means reaching into the attrset that was already returned and pulling out `a`

, which is already `1`

.

That version of `fix`

is efficient, but it’s functionally equivalent to this:

```
fix = f: f (fix f)
```

So maybe you can see how this relates to your observation about `fun (fun { a = 0; })`

, in that it takes it to the extreme and evaluates to infinitely re-apply `fun`

to itself in that manner.

5 Likes