Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How is cond supposed to work? #655

Open
metaleap opened this issue Jul 20, 2024 · 2 comments
Open

How is cond supposed to work? #655

metaleap opened this issue Jul 20, 2024 · 2 comments

Comments

@metaleap
Copy link

metaleap commented Jul 20, 2024

First off, love this project and having a blast with progressing through it! 🎉

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.

@metaleap
Copy link
Author

metaleap commented Jul 21, 2024

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, only def, 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).

@metaleap
Copy link
Author

metaleap commented Jul 22, 2024

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 😵‍💫 my own caseOf formulation works though and as before, all other tests pass ¯\_(ツ)_/¯

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant