Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mapcat using map and concat

In order to better understand mapcat I took an example:

user>  (mapcat #(list % %) [1 2 3])
(1 1 2 2 3 3)

And tried to reproduce what the doc describes using, on purpose, map and concat :

user> (doc mapcat)
clojure.core/mapcat
([f & colls])
  Returns the result of applying concat to the result of applying map
  to f and colls.  Thus function f should return a collection.

By doing this:

user>  (concat (map #(list % %) [1 2 3]))
((1 1) (2 2) (3 3))

However as you can see it doesn't work. I can however use reduce like this but don't know if it's correct:

user>  (reduce #(concat %1 %2) (map #(vec (list % %)) [1 2 3]))
(1 1 2 2 3 3)

The above works but I don't know if it's a correct way to recreate, using map and concat, what mapcat does.

Basically I'd like to understand of mapcat works under the hood.

What is going on and how can I access the source of mapcat? (I'm using Emacs + nrepl)

like image 228
Cedric Martin Avatar asked Nov 05 '12 01:11

Cedric Martin


1 Answers

user=> (source mapcat)
(defn mapcat
  "Returns the result of applying concat to the result of applying map
  to f and colls.  Thus function f should return a collection."
  {:added "1.0"}
  [f & colls]
    (apply concat (apply map f colls)))
nil
user=> 

The reason reduce also works is because it is effectively:

(concat (concat '(1 1) '(2 2)) '(3 3))

apply, as used in the source code, expands to:

(concat '(1 1) '(2 2) '(3 3))

In your initial attempt with concat:

  user=> (map #(list % %) [1 2 3])
  ((1 1) (2 2) (3 3))
  user=> (concat (list '(1 1) '(2 2) '(3 3)))
  ((1 1) (2 2) (3 3))
  user=> (concat [1])
  (1)

You can see that if you call concat with a single argument, it returns that argument.

like image 95
Kyle Avatar answered Oct 14 '22 05:10

Kyle