【发布时间】:2014-03-31 11:40:27
【问题描述】:
在我的小项目中,我有两个数组,我们称它们为 A 和 B。它们的值是
#(1 2 3) 和 #(5 6 7)。我还有两个相同长度的符号列表,我们称它们为 C 和 D。它们看起来像这样:(num1 num2 num3) 和 (num2 num3 num4)。
您可以说列表 C 和 D 中的符号是数组 A 和 B 中值的文本标签。因此 A 中的 num1 为 1。A 中的 num2 为 2。B 中的 num2 为 5。没有 num1在B中,但有一个num3,即6。
我的目标是生成一个带有两个参数的函数,如下所示:
(defun row-join-function-factory (C D)
...body...)
我希望它返回一个有两个参数的函数:
(lambda (A B) ...body...)
这样使用参数 A 和 B 调用的结果函数会产生一种返回新数组的“连接”:#(1 5 6 7)
在后面的函数中发生的过程从两个数组 A 和 B 中获取值,从而生成一个新数组,其成员可以由(union C D) 表示。注意:我实际上并没有运行(union C D),因为我实际上并不关心其中包含的符号的顺序,但假设它返回(num1 num2 num3 num4)。重要的是(num1 num2 num3 num4) 作为文本标签对应于新数组#(1 5 6 7)。如果 num2 或任何符号同时存在于 C 和 D 中,并且随后表示来自 A 和 B 的值,则与该符号对应的来自 B 的值将保留在结果数组中,而不是来自 A 的值。
我希望在这里得到机械动作的要点。从理论上讲,我希望 row-join-function-factory 能够使用任何长度/内容的数组和符号列表来做到这一点,但编写这样的函数并不是我无法做到的,也不是问题。
问题是,我希望返回的函数非常高效,这意味着我不愿意让函数在列表中跟踪指针,或者在运行时查找哈希表。在这个例子中,我需要返回的函数几乎是字面意思:
(lambda (A B)
(make-array 4
:initial-contents (list (aref A 0) (aref B 0) (aref B 1) (aref B 2))))
我不希望在运行时计算数组索引,也不希望它们引用哪个数组。我想要一个编译的函数,它尽可能快地完成这个和这个,它做的工作尽可能少。我不关心制作这样一个功能所需的运行时工作,只关心应用它所需的运行时工作。
我已决定在 row-join-function-factory 中使用 (eval ) 来处理表示上述 lisp 代码的符号以生成此函数。但是,我想知道,考虑到人们对使用 eval 的普遍谨慎态度,是否有一些更简单的方法来实现我没有想到的这个技巧......
根据我的推理,我不能单独使用宏,因为它们无法知道所有值和维度 A、B、C、D 在编译时可以采用什么,而我可以编写一个返回 lambda 的函数,该函数会机械地返回做我想做的事,我相信我的版本总是会做一些额外的运行时工作/关闭变量/等等...与上面假设的 lambda 函数相比
欢迎提出想法、答案、建议等。我的结论是否正确,这是一种罕见的合法 eval 用途?对于我无法用英语雄辩地表达这个问题提前道歉......
(或者,如果有人可以解释我的推理在哪里出错,或者如何动态生成最有效的函数......)
【问题讨论】:
-
请注意:据我所知,宏(没有 eval)本身并不适用,因为 A、B、C、D 的质量可能仅在运行时知道/未来,它们可能会有所不同,并且当宏扩展时它们可能不存在,除非您告诉宏在运行时使用 eval 扩展......(尽管如果我弄错了,我很高兴在这一点上得到纠正) .
标签: common-lisp eval lambda processing-efficiency