This is my code to generate a cartesian product:
(defun cartesian-product (LIST)
(LOOP FOR X IN LIST
NCONC
(LOOP FOR Y IN LIST
COLLECT (LIST X Y))))
I tried outputting one of the cartesian products with this:
(defun cartesian-product-generator (CALLBACK LIST)
(LOOP FOR X IN LIST
NCONC
(LOOP FOR Y IN LIST
DO(FUNCALL CALLBACK (LIST X Y)))))
However there are errors when I tried testing it with:
(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).
I am new to LISP and would like to know why there's an error and how to fix this error. Ultimately, I would like to output each cartesian product per call of the function.
For example, if the lists consists of ((1 1) (1 2) (2 1) (2 2))
.
I would like to generate (1 1)
. Then (1 2)
. Then (2 1)
. Lastly, (2 2)
.
Your first code does work correctly.
(defun cartesian-product (list)
(loop
for x in list
nconc (loop for y in list
collect (list x y))))
Calling it with '(a b c)
returns a list:
((A A) (A B) (A C) (B A) (B B) (B C) (C A) (C B) (C C))
You want to avoid building a list and use a callback instead. To simplify, first try to only print elements instead of collecting them.
That means that you do not care about returning the generated values up to the caller: you just want to generate them and print them as soon as they are available.
Basically, you can replace all nconc
and collect
keywords by do
, and add a call to print
:
(defun cartesian-product (list)
(loop
for x in list
do (loop for y in list
do (print (list x y)))))
A quick test on the REPL with '(a b c)
should print the same
elements as previously, each one on a separte line.
Now, you can just generalize print
and call anything you want:
(defun map-cartesian-product (function list)
(loop
for x in list
do (loop for y in list
do (funcall function (list x y)))))
Just to see if it still works, do a quick test:
(map-cartesian-product #'print '(a b c))
This should have the same behaviour as before.
Since you only iterate over a list for side-effects, you can use
DOLIST
:
(defun map-cartesian-product (function list)
(dolist (x list)
(dolist (y list)
(funcall function (list x y)))))
Again, you can test that it still works as previously.