Search code examples
clojure

How does a macro work if it returns a sequence instead of a list?


I came across this macro definition for unless from the brave and true book

(defmacro unless
  "Inverted 'if'"
  [test & branches]
  (conj (reverse branches) test 'if))

I believe the rest param is a sequence, and the conj returns a sequence, so this entire macro returns a sequence. I thought you needed to return a list for the return to be evaluated properly

On further investigation, why does (eval (sequence [+ 1 4 4])) do the same thing as (eval (list 1 4 4)). Where does it say that sequences are evaluated like lists? I don't see that in the docs. –


Solution

  • You have just proven that a list, a seq, and a sequence are all treated as function call sites by the Clojure compiler. That is your answer.

    => (def xxx [+ 2 3])  ; a function and 2 integers in a vector
    
    => (eval xxx) ; a vector doesn't work
    [#object[clojure.core$_PLUS_ 0x375dfecb "clojure.core$_PLUS_@375dfecb"] 2 3]
    
    => (eval (seq xxx))  ; a seq works
    5
    
    => (eval (sequence xxx))  ; a sequence works
    5
    
    => (eval (apply list xxx))  ; converts xxx to a list  (+ 2 3)  which works
    5
    

    When the Clojure docs are ambiguous or are missing some detail, a small experiment like the above will answer your question.

    If the answer applies to a specific area of the Clojure website, function docstring, or clojuredocs.org or clojure-doc.org, you may consider submitting a pull-request to update & improve the docs.