Nix的“callPackage”如何调用没有省略号定义的函数?

8

要调用一个使用set解构的Nix函数,你需要传递一个含有准确所需键的set,不能多也不能少:

nix-repl> ({ a }: a) { a = 4; b = 5; }
error: anonymous function at (string):1:2 called with unexpected argument ‘b’, at (string):1:1

唯一的例外是,如果函数的参数列表末尾包含省略号:

nix-repl> ({ a, ... }: a) { a = 4; b = 5; }
4

然而,大多数在 nixpkgs 中的软件包都由一个包含函数的default.nix文件组成,这个函数没有使用省略号来定义。但是,当您使用callPackage时,它会调用这些函数并传递它们所需的参数。这是如何实现的呢?

对于任何想知道 callPackage 实现在哪里(以及如何找到 lambda 定义)的人,请参见此答案:https://dev59.com/QrPma4cB1Zd3GeqPw9na#56124590 - toraritte
1个回答

9

有一种反射 primop,可以解构函数参数:

nix-repl> __functionArgs ( { x ? 1, y }: x )
{ x = true; y = false; }

callPackage函数会遍历这些属性名称,获取所需的软件包并构建软件包的属性集,然后将其传递给调用的函数。

以下是一个简单的示例:

nix-repl> callWithExtraArgs = f: args:
            let
              args' = __intersectAttrs (__functionArgs f) args;
            in
              f args'

nix-repl> callWithExtraArgs ({ x }: x + 1) { x = 4; y = 7; }
5

要浏览 Nix primops,请前往15.5. 内置函数Nix 手册中(或参见不稳定分支的文档)。


最初我在上面的编辑中添加了一行“__functionArgsbuiltins.functionArgs相同”,因为它们在nix repl中都评估为«primop»,但是trivial.nix中的注释和代码让我对这个说法感到不确定。(链接显示setFunctionArgs,因为我无法理解它的看似循环的定义...)__intersectAttrsbuiltins.intersectAttrs也是如此。 - toraritte
1
@toraritte,它们是相同的,只是lib.nix adds __functionArgs 属性来模拟内置的__functionArgs。这样可以将实际的__functionArgs结果传递给消费者,因为内置的__functionArgs只能在最顶层的函数参数中起作用。是啊,感觉有点绕。 - danbst

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接