How is `cond` supposed to work?
First off, love this project and having a blast with progressing through it! :tada:
Well, after the first 8 chapters, I now got all the macro, quasiquotation etc tests working except for cond tests: expansion of cond (even just by doing macroexpand in REPL) will have my if special-form (that the macro body is clearly calling) erroring on wrong arg count (2 instead of 3).
And no wonder, looking at cond as defined in process/step8_macros.txt, just indented:
(def cond
(macro (& xs)
(if (> (count xs) 0)
(list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw "odd number of forms to cond")) (cons 'cond (rest (rest xs)))))))
The if has no "else-branch arg" (the 3rd).
Now what? I must be missing something here?
For reference, here are my macroexpand and eval and quasiquote/unquote.
Like I said, all tests of steps 1 through 8 succeed, except the cond stuff.
Well, I wrote one from scratch that words for me and expands correctly
- just not variadic which I don't much care for anyway;
- minor idiosyncrasies: my MAL doesn't have
defmacro, onlydef, and my false/true/nil are:keywords
(def caseOf
(macro (cases)
(if (isEmpty cases)
:nil
(let ( (this_case (nth cases 0))
(case_cond (nth this_case 0))
(case_then (nth this_case 1)))
`(if ~case_cond
~case_then
(caseOf ~(rest cases)))))))
Seems to work well:
࿊ (macroExpand (caseOf [ [:false (do (print :nay) :nope)] [:true (do (print :yay) (+ 1 2))] ]))
(if :false (do (print :nay) :nope) (caseOf ([:true (do (print :yay) (+ 1 2))])))
࿊ (caseOf [ [:false (do (print :nay) :nope)] [:true (do (print :yay) (+ 1 2))] ])
:yay3
Anyone see any issues with that? Also, still eager to learn what I was missing about MAL's own cond! Surely it isn't actually butchered and just looked that way to under-informed me (and my MAL impl).
Update: only now noticed that MAL's if has the 3rd arg as optional, missed that part before. Still, having updated my MAL impl to use :nil for a missing 3rd if arg, the cond as originally formulated:
(def cond
(macro (& xs)
(if (> (count xs) 0)
(list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw "odd number of forms to cond")) (cons 'cond (rest (rest xs)))))))
still results in a stack overflow with 2 args or more :face_with_spiral_eyes: my own caseOf formulation works though and as before, all other tests pass ¯\_(ツ)_/¯