3 points by mpr 597 days ago | link | parent I think the double assignment of the names given to the labels macro is needed in the case that the functions call each other. Take this example:`````` (labels ((even (n) (if (is n 0) 'even (odd (- n 1)))) (odd (n) (if (is n 0) 'odd (even (- n 1))))) (even 5)) `````` The macroexpansion of this labels call looks like this`````` ((fn (g3947 g3948) (with (even (fn a (apply g3947 a)) odd (fn a (apply g3948 a))) (with (even (fn (n) (if (is n 0) (quote even) (odd (- n 1)))) odd (fn (n) (if (is n 0) (quote odd) (even (- n 1))))) (do (= g3947 even) (= g3948 odd)) (even 5)))) (fn nil nil) (fn nil nil)) `````` If I add a prn to see what we get, we can run the code and see that it works as expected.`````` (prn ((fn (g3947 g3948) (with (even (fn a (apply g3947 a)) odd (fn a (apply g3948 a))) (with (even (fn (n) (if (is n 0) (quote even) (odd (- n 1)))) odd (fn (n) (if (is n 0) (quote odd) (even (- n 1))))) (do (= g3947 even) (= g3948 odd)) (even 5)))) (fn nil nil) (fn nil nil))) ;; odd `````` Now I will remove the outer with and run the same code, which returns nil.`````` (prn ((fn (g3947 g3948) (with (even (fn (n) (if (is n 0) (quote even) (odd (- n 1)))) odd (fn (n) (if (is n 0) (quote odd) (even (- n 1))))) (do (= g3947 even) (= g3948 odd)) (even 5))) (fn nil nil) (fn nil nil))) ;; nil `````` I can't explain this in greater detail; I haven't traced the full execution. But given the evidence I believe mutual recursion makes double assignment necessary.
 4 points by akkartik 597 days ago | link You could macroexpand to this, though:`````` (with (even nil odd nil) (= even (fn (n) (if (is n 0) 'even (odd (- n 1)))) odd (fn (n) (if (is n 0) 'odd (even (- n 1))))) (even 5))``````-----
 3 points by mpr 597 days ago | link Yes, this simpler macroexpansion is all that's needed, apparently. When I first ported the code above I didn't have an appreciation for what labels needed to do; I just ported it. Thanks for making me think about it a little harder. Here is an implementation that will macroexpand to only one with. I've included a sample macroexpansion, as well as the results of running two functions. One of them, (collatz-seq), uses only simple recursion. The other, (parity), uses mutual recursion.`````` (mac labels (fns . forms) (with (fnames (map car fns) fbodies (map (fn (f) `(fn ,@(cdr f))) fns)) `(with ,(mappend (fn (name) `(,name nil)) fnames) (= ,@(mappend (fn (f) `(,(car f) ,@(cdr f))) (zip fnames fbodies))) ,@forms))) (def collatz-seq (n) (labels ((collatz (n) (if (even n) (/ n 2) (+ (* n 3) 1))) (worker (n seq) (if (is n 1) (cons n seq) (worker (collatz n) (cons n seq))))) (rev (worker n '())))) (def parity (n) (labels ((even (n) (if (is n 0) 'even (odd (- n 1)))) (odd (n) (if (is n 0) 'odd (even (- n 1))))) (even n))) (prn (macex1 '(labels ((even (n) (if (is n 0) 'even (odd (- n 1)))) (odd (n) (if (is n 0) 'odd (even (- n 1))))) (even n)))) (prn (parity 17)) (prn (parity 24)) (prn (collatz-seq 21)) ;; --------------------------------------------- ;; (with (even nil odd nil) ;; (= even (fn (n) ;; (if (is n 0) ;; (quote even) ;; (odd (- n 1)))) ;; odd (fn (n) ;; (if (is n 0) ;; (quote odd) ;; (even (- n 1))))) ;; (even n)) ;; ;; odd ;; even ;; (21 64 32 16 8 4 2 1)``````-----