This is a read-only archive of lispforum.com. The forum was locked to new users and posts and is preserved here as static HTML from a database snapshot taken on 2019-09-07.

can print from dotimes (nth...) but that's all

5 posts · 991 views

Hi there. This is my code:
(defun cartesian-product (m n)
	(defun helper (x)
	  (setf k n)
	  (dotimes (i (length n))
	    (setq j (nth i k))
	    (print (cons x (cons j nil)))))
	(mapcar #'helper m))
The output for '(a b) and '(c d) is
(A C) 
(A D) 
(B C) 
(B D) 
(NIL NIL)
After much wrestling, it does make a Cartesian product of any 2 lists!

However I need it to return a list. I have tried to
(append (cons x (cons j nil) 
in place of printing, but that returns (nil) (nil)

Help?

Thanks. :)

Re: can print from dotimes (nth...) but that's all

There is a problem with your code. You can't used defun inside a function. In your case, the function "helper" defined is global, not local to "cartesian-product". Instead, you should use flet or labels (use labels if the function is going to be recursive).

Also, local variables must be declared. Again, the variables "k" and "j" in your code are global (or might not even be created). You should declare variables with let or let*.

You are iterating over a list like you would iterate over an array. Don't do this, lists are accessed sequentially, not by index. Instead of "dotimes" and "nth", use "dolist". You don't need neither of the variables j nor k for that matter.

Finally, instead of "cons" inside "cons", there is "list".

This is how your code looks like after those changes:
(defun cartesian-product (m n)
  (flet ((helper (x)
           (dolist (j n)
             (print (list x j)))))
    (mapcar #'helper m)))
This function does what yours does.

Now, instead of printing, how about pushing the elements into a new list?
(defun cartesian-product (m n)
  (let ((new-list nil)) ; nil is the empty list
    (flet ((helper (x)
             (dolist (j n)
               (push (list x j)
                     new-list))))
      (mapcar #'helper m))
    ;; Needs to return the new-list at the end!!!
    new-list))
Please note that, when you use "append" and other functions that operate on lists, they do not update the value of their arguments! Instead, they return the new list, so you need to fetch the value returned somewhere (into a new variable, as returned-value or to a function call).

"Push" is an exception that updates its second argument because it is not a function, it's a macro that is equivalent to. Only macros (like "setf") can do that. This is what "push" does:
(push element list) === (setf list (cons element list))
Lisp is this: functions computing and returning values (functional paradigm), not functions doing stuff and changing the values of the variables (imperative paradigm). Of course Lisp has a bit of both paradigms (and others as well), but each paradigm has its place, and imperative don't take place at simple operations on lists.

Re: can print from dotimes (nth...) but that's all

Thank you so much.

I was really struggling because I didn't know what I needed to be learning how to do. Thanks for telling me about flet, and how to return the list at the end! Also thanks for explaining to me about append versus push.

It's really hard to google LISP stuff sometimes because you turn up heaps of scheme and emacs lisp answers that don't quite work in clisp.

THANKS!!! :D

TG

Re: can print from dotimes (nth...) but that's all

If you want to learn Common Lisp I recommend the book Practical Common Lisp.

Re: can print from dotimes (nth...) but that's all

Here's what I use for Cartesian product. It is a slight modification of some code I found on comp.lang.lisp some time ago.
(defun cartesian-product (list1 list2)
  "Return a list of the Cartesian product of two lists."
  (mapcan (lambda (x) (mapcar (lambda (y) (list x y)) list2)) list1))
Hope that helps.

~ Tom
Thomas M. Hermann
Odonata Research LLC
http://www.odonata-research.com/
http://www.linkedin.com/in/thomasmhermann