-
-
Notifications
You must be signed in to change notification settings - Fork 14.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
lib.lazyFunction: init #194514
base: master
Are you sure you want to change the base?
lib.lazyFunction: init #194514
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,9 @@ | ||
{ lib }: | ||
|
||
let | ||
inherit (lib) mapAttrs functionArgs setFunctionArgs; | ||
in | ||
|
||
rec { | ||
|
||
## Simple (higher order) functions | ||
|
@@ -467,6 +471,50 @@ rec { | |
then v | ||
else k: v; | ||
|
||
/* | ||
Make a function lazy in its argument. | ||
|
||
Normally when you call a function `f` like `{ a, b }: { r = foo a b; }`, | ||
the attribute names of the argument must be evaluated before the evaluator | ||
can return a the (partially evaluated) function body (`{ r = ...; }`). | ||
|
||
`lazyFunction` wraps this kind of function in such a way that this strict | ||
behavior is cancelled out. With the example `f` above, `lazyFunction f` returns | ||
`arg: f { a = arg.a; b = arg.b; }`. | ||
|
||
You can see that this wrapper function always satisfies `f`'s parameter | ||
attributes `a` and `b`, but the expressions for them may still fail later. | ||
For example `arg` may not contain an attribute `a`, or not even be an | ||
attribute set. | ||
|
||
Limitations: | ||
|
||
`lazyFunction` only works for functions that are either defined using the | ||
"set pattern" Nix syntax, or returned from `lib` functions that preserve | ||
function argument metadata | ||
|
||
It is not compatible with ellipsis patterns, `{ ... }:`, because only the | ||
explicitly declared parameters are passed through. For example, the | ||
following will not work: `lazyFunction(arg@{ a, ... }: arg.b)`; | ||
even if the caller provides `b`. | ||
|
||
It also removes the checks against unexpected arguments. | ||
|
||
Example: | ||
|
||
lib.fix (lib.lazyFunction ({ a, b }: { a = b; b = 1; })) | ||
*/ | ||
lazyFunction = f: | ||
setFunctionArgs | ||
(arg: | ||
f | ||
(mapAttrs | ||
(k: _: arg.${k}) | ||
(functionArgs f) | ||
) | ||
) | ||
(functionArgs f) ; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could try to prevent some misuse by throwing an error when There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That could be a problem if someone uses There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Super bad example, but better than no example? let
testCase.foo = { a }: a * 2 == a + a;
testCase.bar = { }: true;
in mapAttrs (k: lazyFunction) testCase |
||
|
||
/* Convert the given positive integer to a string of its hexadecimal | ||
representation. For example: | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've rewritten a lot to make better use of the example instead.