Reputation: 5464
I understand the following snippet of code and its corresponding output
(let [ [x y] (map list [1 2] [3 4])] (prn x) (prn y))
(1 3)
(2 4)
nil
Now the following output confuses me:
(doseq [ [x y] (map list [1 2] [3 4])] (prn x y))
1 3
2 4
nil
I think in the above snippet x will get bound to [1 3] and y will get bound to [2 4] so the output should be"
1 2
3 4
nil
Upvotes: 2
Views: 383
Reputation: 13473
Let's isolate the source of your confusion.
(map list [1 2] [3 4])
evaluates to
((1 3) (2 4))
So your first example
(let [[x y] (map list [1 2] [3 4])] (prn x) (prn y))
... is equivalent to
(let [[x y] [[1 3] [2 4]]] (prn x) (prn y))
... or, printing slightly differently
(let [[x y] [[1 3] [2 4]]] (prn [x y]))
... which simplifies to
(let [z [[1 3] [2 4]]] (prn z))
... producing, as expected,
; [[1 3] [2 4]]
; nil
So far, so good.
If we boil down the confusing example,
(doseq [ [x y] (map list [1 2] [3 4])] (prn x y))
... in the same way, we get, taking the liberty of printing each z
whole,
(doseq [z [[1 3] [2 4]]] (prn z))
which fairly clearly produces the observed order:
[1 3]
[2 4]
nil
The difference is that the doseq
binds z
to each successive vector in [[1 3] [2 4]]
, so we don't see an enclosing [ ... ]
, whereas the let
binds z
once to the whole thing.
Upvotes: 3
Reputation: 24750
The binding is pulling out the individual elements inside the larger single element in the nesting. The map creates a list ((1 3) (2 4)
so the element 1 3
is first and thus that is what the doseq outputs: this is "destructuring" and the x
and y
are both bound from inside a single element of the list. Thus x and y are 1 and 3, and then 2 and 4.
Note also that this is the same binding that occurs in a for
and the destructuring works for all sequence types.
Upvotes: 3