1

According to the Learning Clojure wikibook backticks are expanded as follows

`(x1 x2 x3 ... xn)

is interpreted to mean

(clojure.core/seq (clojure.core/concat |x1| |x2| |x3| ... |xn|))

Why wrap concat with seq? What difference does it make?

Matthew Molloy
  • 1,166
  • 1
  • 10
  • 22

2 Answers2

1

Regardless of how it arose

  • concat returns a sequence, and
  • seq returns a sequence with the same content as its sequence argument,

... so seq is effectively an identity-op on a concat... except in one circumstance:

When s is an empty sequence, (seq s) is nil.

I doubt that the expansion is correct, since

`()

... evaluates to

()

... with type

clojure.lang.PersistentList$EmptyList

Whereas

(seq (concat))

... evaluates to

nil

This suggests that the wrapping call to seq is not there.

Thumbnail
  • 13,293
  • 2
  • 29
  • 37
  • This is not true. Empty lists are retained: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/LispReader.java#L837 - The call to seq is there. It's all over it. – Leon Grapenthin Nov 01 '14 at 11:46
  • @LeonGrapentin So far as I can see, my answer is correct and you have confirmed so. My point is that **the proposed expansions** are at fault. As you say, *empty lists are retained*. I agree: *It's there in my answer - as an explicit example.* They would not be if the the expansion in the question or in [@Chiron's answer](http://stackoverflow.com/a/26671421/1562315) prevailed. I haven't a clue how this happens in the compiler. Looking at the code you refer to, the result is `RT.cons(LIST,null)`. This might return `null`, but we **know** it doesn't. – Thumbnail Nov 01 '14 at 15:41
  • Look at all the other cases above line 837 - also the else to line 837 - they all wrap a list beginning with seq. This is how it happens in the *reader*. – Leon Grapenthin Nov 01 '14 at 17:56
  • @LeonGrapenthin Nevertheless, the proposed expansions are invalid, for the reasons stated. What is actually wrong *in the answer*? – Thumbnail Nov 02 '14 at 10:08
  • The proposed expansions are correct. ``()` is read as `()` because an exception is made for it. In all other cases `seq` is wrapped. – Leon Grapenthin Nov 02 '14 at 13:04
  • @LeonGrapenthin ... so in the only case in which it would make a substantive difference *to the interpretation of back-tick referred to in the question*, the enclosing `seq` call isn't there? – Thumbnail Nov 02 '14 at 13:27
  • @LeonGrapenthin ... so a trifling defect in the reader: generating a redundant enclosing `seq` form - except where it would have some effect - translates into an extremely confusing - because incomplete - explanation. Yet all concerned are doing their best to be clear and accurate. – Thumbnail Nov 02 '14 at 14:09
  • The exception is made if an empty list is explicitly read. Otherwise the result of further macroexpansion is always wrapped in seq concat. E. g. ` `(~@())` yields nil. – Leon Grapenthin Nov 03 '14 at 15:58
-1

Strictly speaking, it expands to:

(macroexpand '`(x1 x2 x3))
(clojure.core/seq (clojure.core/concat (clojure.core/list (quote user/x1)) (clojure.core/list    (quote user/x2)) (clojure.core/list (quote user/x3))))

(macroexpand `(x1 x2 x3))
(user/x1 user/x2 user/x3)

Why the call seq ? Because sequences are corner stones in Clojure philosophy. I recommend you read Clojure Sequences. Otherwise, I would duplicate it here.

Chiron
  • 20,081
  • 17
  • 81
  • 133