这是我生成笛卡尔积的代码:
(defun cartesian-product (LIST)
(LOOP FOR X IN LIST
NCONC
(LOOP FOR Y IN LIST
COLLECT (LIST X Y))))
我尝试输出其中一个笛卡儿产品:
(defun cartesian-product-generator (CALLBACK LIST)
(LOOP FOR X IN LIST
NCONC
(LOOP FOR Y IN LIST
DO(FUNCALL CALLBACK (LIST X Y)))))
但是当我尝试使用以下测试时出现错误:
(cartesian-product-generator '(A B C))
Error: Too few arguments in call to #<Compiled-function cartesian-product-generator #x30200097E60F>:
1 argument provided, at least 2 required. While executing: cartesian-product-generator, in process listener(1).
我是LISP的新手,想知道为什么会出现错误以及如何解决此错误。最终,我希望每次调用函数输出每个笛卡尔积。
例如,如果列表包含((1 1) (1 2) (2 1) (2 2))
。
我想生成(1 1)
。然后是(1 2)
。然后是(2 1)
。最后,(2 2)
。
答案 0 :(得分:5)
您的第一个代码可以正常运行。
(defun cartesian-product (list)
(loop
for x in list
nconc (loop for y in list
collect (list x y))))
使用'(a b c)
调用它会返回一个列表:
((A A) (A B) (A C) (B A) (B B) (B C) (C A) (C B) (C C))
您希望避免构建列表并改为使用回调。 为简化起见,首先尝试仅打印元素而不是收集它们。
这意味着你不关心关于返回生成的值 直到调用者:你只想生成它们并将它们打印出来 他们有空的时候。
基本上,您可以按nconc
替换所有collect
和do
个关键字,并添加对print
的调用:
(defun cartesian-product (list)
(loop
for x in list
do (loop for y in list
do (print (list x y)))))
使用'(a b c)
对REPL进行快速测试时应该打印相同的内容
以前的元素,每个元素都在一个separte行。
现在,您可以概括print
并调用您想要的任何内容:
(defun map-cartesian-product (function list)
(loop
for x in list
do (loop for y in list
do (funcall function (list x y)))))
只是看它是否仍然有效,快速测试一下:
(map-cartesian-product #'print '(a b c))
这应该具有与以前相同的行为。
由于您只遍历列表中的副作用,因此您可以使用
DOLIST
:
(defun map-cartesian-product (function list)
(dolist (x list)
(dolist (y list)
(funcall function (list x y)))))
同样,你可以测试它仍然像以前一样工作。
答案 1 :(得分:2)
您可能希望通过cl-coroutine
查看可用的quicklisp
库。然后您的cartesian-product
可以写成
(cl-coroutine:defcoroutine cartesian-product (list)
(loop for x in list
do (loop for y in list
do (cl-coroutine:yield (list x y)))))
示例用法可以是:
(cl-coroutine:with-coroutine (cartesian-product)
(let ((x (list 1 2 3)))
(loop for y = (cartesian-product x)
while y do (print y))))
; outputs (1 1) (1 2) ... (3 3)