This is a nice application for easy macro recursion:
(defmacro count-true (&rest forms) (cond ((null forms) 0) ((endp (rest forms)) `(if ,(first forms) 1 0)) (t `(+ (count-true ,(first forms)) (count-true ,@(rest forms))))))
Tests:
[2]> (count-true) 0 [3]> (count-true nil) 0 [4]> (count-true t) 1 [5]> (count-true nil t) 1 [6]> (count-true t nil) 1 [7]> (count-true tt) 2 [8]> (count-true nil nil) 0 [9]> (macroexpand '(count-true)) 0 ; T [10]> (macroexpand '(count-true x)) (IF X 1 0) ; T [11]> (macroexpand '(count-true xy)) (+ (COUNT-TRUE X) (COUNT-TRUE Y)) ; T [12]> (macroexpand '(count-true xyz)) (+ (COUNT-TRUE X) (COUNT-TRUE YZ)) ; T
A macro should talk about syntax input and generate a code that performs the calculation; You should not mix between code generation and evaluation.
You are mistaken right after you do this:
`(cond ((null ,forms ...) ...)
you push the metasyntactic calculation (how many forms do we have in the syntax?) into the generated code template is evaluated at runtime. In this basic case, you have the correct pieces, but they are not set correctly. In my solution, I have cond only in the macro object itself, and not in the backquote:
(cond ((null forms) ...) ...)
Basically:
(cond (<if the syntax is like this> <generate this>) (<if the syntax is like that> <generate that>) ...)
If you do not know what to do, write the code that you want to write to the macro. For example:
;; I want this semantics: (if (blah) 1 0) ;; count 1 if (blah) is true, else 0 ;; But I want it with this syntax: (count-true (blah))
Ok, so for this exact case we will write:
(defmacro count-true (single-form) `(if ,single-form 1 0))
Done! Suppose we want to support (count-true) without any form.
Wanted Syntax Translation (count-true) 0 (count-true x) (if x 1 0)
When there is a form, the if extension remains, but when there is no form, we just need a constant zero. Easy, make the argument optional:
(defmacro count-true (&optional (single-form nil have-single-form)) (if have-single-form `(if ,single-form 1 0) ;; same as before 0)) ;; otherwise zero
Finally, we turn to the N-ary form:
Wanted Syntax Translation (count-true) 0 (count-true x) (if x 1 0) (count-true xy) (+ (if x 1 0) (if y 1 0)) ^^^^^^^^^^ ^^^^^^^^^^
But! now note that the underlined terms correspond to the output of a single case.
(count-true xy) (+ (count-true x) (count-true y))
What summarizes
(count-true xyz ...) (+ (count-true x) (count-true yz ...))
This corresponds to a direct code generation pattern with car/cdr recursion:
`(+ (count-true ,CAR) (count-true ,*CDR))