更通用的 Lisp 代码来生成对的组合
考虑到下面这个悲伤的事情,它生成仅两个范围的所有对 -
[53]> (setq thingie '())
NIL
[54]> (loop for i in (generate-range 0 3) do
(loop for j in (generate-range 4 6) do
(push (list i j) thingie)))
NIL
[55]> thingie
((3 6) (3 5) (3 4) (2 6) (2 5) (2 4) (1 6) (1 5) (1 4) (0 6) (0 5) (0 4))
[56]>
或者,换句话说,这会生成某种二维离散布局。
我将如何构建某种采用任意范围数量的对生成代码? (或者生成一个n维离散布局)。
显然,一个解决方案是使用一个 defmacro 来获取列表列表并构建 n 个循环来执行,但这感觉不是一个简单的方法。
Given this sad thing below, which generates all pairs of only two ranges -
[53]> (setq thingie '())
NIL
[54]> (loop for i in (generate-range 0 3) do
(loop for j in (generate-range 4 6) do
(push (list i j) thingie)))
NIL
[55]> thingie
((3 6) (3 5) (3 4) (2 6) (2 5) (2 4) (1 6) (1 5) (1 4) (0 6) (0 5) (0 4))
[56]>
Or, put another way, this generates sort of a two-dimensional discrete layout.
How would I go about building some sort of pairs-generating code that took arbitrary numbers of ranges? (Or generating an n-dimensional discrete layout).
Obviously one solution would be to have a defmacro
that took a list-of-lists and built n loops for execution, but that doesn't feel a straightforward way to go.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
如果您更喜欢语法糖,
请编辑:(简要说明)
gn 的第一个参数 x 是迄今为止构造的部分元组; y 是剩余的元素袋。函数 gn 通过迭代剩余包之一 (car y) 的每个元素 i 来扩展部分元组,以形成 (cons ix)。当没有剩余的包时(if语句的else分支),元组就完成了,因此我们在元组上调用提供的函数fn。
If you prefer syntax sugar,
Edit: (brief explanation)
The first parameter of gn, x, is the partial tuple constructed so far; y is the remaining bags of elements. The function gn extends the partial tuple by iterating over each element i of one of the remaining bags, (car y), to form (cons i x). When there's no remaining bags (the else branch of the
if
statement), the tuple is completed, so we invoke the supplied function fn on the tuple.对我来说显而易见的是递归函数。
The obvious thing for me would be a recursive function.
如果您将其视为一种控制结构,那么宏路线就是正确的选择。如果您将其视为生成数据的一种方式,那么递归函数就是最佳选择。
If you're thinking of this as a control structure, the macro route is the way to go. If you're thinking of this as a way of generating data, a recursive function is the way to go.
您不需要显式递归(甚至不需要宏),这也可以使用高阶函数来完成:
两个嵌套的内部高阶函数(
mapcan
和mapcar) 执行与示例中的两个嵌套循环相同的功能。然后,外部高阶函数
reduce
将首先将前两个范围的值组合成对,然后在每次调用其参数函数时再次将某个过程应用于前面的中间结果调用和下一个范围。You don't need explicit recursion (or even a macro), this can also be done with a higher-order function:
The two nested inner higher-order functions (
mapcan
andmapcar
) perform the same function that the two nested loops in your example did. The outer higher-order functionreduce
will then first combine the values of the first two ranges to pairs, and after that in each invocation of its argument function apply the some process again to the intermediate results from the preceding invocation and the next range.