Page 1 of 1

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

Posted: Fri Aug 13, 2010 6:27 pm
by titanium_geek
Hi there. This is my code:

Code: Select all

(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

Code: Select all

(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

Code: Select all

(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

Posted: Fri Aug 13, 2010 7:42 pm
by gugamilare
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:

Code: Select all

(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?

Code: Select all

(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:

Code: Select all

(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

Posted: Fri Aug 13, 2010 8:37 pm
by titanium_geek
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

Posted: Sat Aug 14, 2010 5:43 am
by gugamilare
If you want to learn Common Lisp I recommend the book Practical Common Lisp.

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

Posted: Sat Aug 14, 2010 6:18 pm
by Tom
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.

Code: Select all

(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