Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
comparing every element in a list to every other element
; common lisp version, totally works
; (defun build (list1 list2)
; (if (null list1)
; ()
; (append (mapcar #'(lambda (bubble)
; (list (first list1) bubble))
; list2)
; (build (rest list1) list2))))
; if you tell lisp: (build '(1 2) '(1 2))
; lisp will happily reply: ((1 1) (1 2) (2 1) (2 2))
; literal clojure translation
(defn build [list-1 list-2]
(if (nil? list-1)
(concat (map (fn [bubble]
(list (first list-1) bubble))
(build (rest list-1) list-2))))
; if you tell clojure: (build '(1 2) '(1 2))
; lisp will stack overflow error all up in your business
; if you're curious there's a Ruby version here:

gilesbowkett commented Jun 30, 2013

recur also fails because it's not in the tail position

The problem is that the empty list returns false to nil? in Clojure. () and nil are distinct. So it's going into an infinite loop.

Should do (nil? (seq list-1)) instead.

Or do (when (seq list-1) (concat ....))

candera commented Jun 30, 2013

This looks like you're trying to take the Cartesian cross-product of two sequences. I know you got help on the failure already, but in case you're interested, a more Clojurey approach would look like this:

(defn build [seq1 seq2]
  (for [elem1 seq1 elem2 seq2] [elem1 elem2]))

And that's short enough that I probably wouldn't even bother making a function out of it.

If you want something that's the Cartesian product of n sequences, that's slightly more involved:

(defn cross-prod [& colls]
  (->> colls
       (reduce #(for [x %1 y %2] [x y]))
       (map flatten)))

lispm commented Jan 8, 2015

The Common Lisp code reimplements MAPCAN. Use it:

(defun cp (l1 l2)
  (mapcan (lambda (e2)
            (mapcar (lambda (e1) (list e1 e2)) l1))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment