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

Discussion of Common Lisp
Post Reply
titanium_geek
Posts: 7
Joined: Mon Feb 01, 2010 7:48 pm

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

Post by titanium_geek » Fri Aug 13, 2010 6:27 pm

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. :)

gugamilare
Posts: 406
Joined: Sat Mar 07, 2009 6:17 pm
Location: Brazil
Contact:

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

Post by gugamilare » Fri Aug 13, 2010 7:42 pm

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.

titanium_geek
Posts: 7
Joined: Mon Feb 01, 2010 7:48 pm

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

Post by titanium_geek » Fri Aug 13, 2010 8:37 pm

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

gugamilare
Posts: 406
Joined: Sat Mar 07, 2009 6:17 pm
Location: Brazil
Contact:

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

Post by gugamilare » Sat Aug 14, 2010 5:43 am

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

Tom
Posts: 22
Joined: Sat Jun 28, 2008 12:52 pm
Location: Wichita, KS
Contact:

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

Post by Tom » Sat Aug 14, 2010 6:18 pm

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

Post Reply