5 ms·
Common Lisp: Macroexpand-time branching
- clock99 5y ago
- gwern 5y agoIs scrolling broken in Firefox 95.0.1 for anyone else on this site? I have to kill sticky elements before I get anything working, but that just leads to a huge amount of console errors from preview JS.
- capableweb 5y agoSame here on 95.0.2 (64-bit) for Arch. Works if I run `document.body.children[9].remove()` manually in the JS console.
- nerdponx 5y agoWorks for me in 95.0.2.
- deleted 5y ago[deleted]
- mftb 5y agoScrolling seemed to work for me. FF 95.0.2
- edhelas 5y agoHi, Movim author there. I can't reproduce your issue, however please check if its not caused by one of your browsers plugins (NoScript, UBlock, Tampermonkey...), I already had similar issues before
- twoodfin 5y agoI probably don't have the Common Lisp chops to comprehend them, but is any implementation of these macros available to browse?
- Jtsummers 5y agoLinked at the end of the blog: https://github.com/phoe/with-branching https://github.com/phoe/with-branching
- kazinator 5y agoYes; there is a link to the github repo. The code isn't rocket science. It has a list of Boolean variables given to the macro, which has to just iterate over their combinatorial possibilities, and generate multiple copies of the enclosed code in which different combinations of values are bound to those variable symbols. E.g. along these lines: (hoist (a b) (code a b)) -> (cond ((and (not a) (not b)) (symbol-macrolet ((a nil) (b nil)) (code a b))) ((and (not a) b)) (symbol-macrolet ((a nil) (b t)) (code a b))) ((and a (not b)) (symbol-macrolet ((a t) (b nil)) (code a b))) ((and a b)) (symbol-macrolet ((a t) (b t)) (code a b)))) The macrolet will propagate the constants into the code, so that it turns into (code nil nil), (code nil t) and so on. Ordinary let could be used, since compilers can do constant propagation without macro assistance. The actual code looks overcomplicated; it's defining its own branching constructs, rather than trusting the compiler to do constant folding. Basically, unless your compiler sucks (in which case, what is the point), all you have to do is convert this: (+ x y (if huge-p 0 100)) ;; huge-p run-time value to this: (let ((huge-p t)) ... (+ x y (if huge-p 1000 0)) and trust the compiler to be smart enough to notice that huge-p is a constant, so that the expression can be folded to (+ x y 1000) There is no need to define any macros that imitate if, while, etc. Quick and dirty implementation: (defun hoist-expander (vars body) (if (null vars) `(progn ,@body) `(if ,(car vars) (symbol-macrolet ((,(car vars) t)) ,(hoist-expander (cdr vars) body)) (symbol-macrolet ((,(car vars) nil)) ,(hoist-expander (cdr vars) body))))) (defmacro hoist ((&rest bool-vars) &body body) (hoist-expander bool-vars body)) > (macroexpand '(hoist (a b) (lambda (arg) (if a (if b arg (foo arg)) (bar arg))))) (IF A (SYMBOL-MACROLET ((A T)) (IF B (SYMBOL-MACROLET ((B T)) (PROGN (LAMBDA (ARG) (IF A (IF B ARG (FOO ARG)) (BAR ARG))))) (SYMBOL-MACROLET ((B NIL)) (PROGN (LAMBDA (ARG) (IF A (IF B ARG (FOO ARG)) (BAR ARG))))))) (SYMBOL-MACROLET ((A NIL)) (IF B (SYMBOL-MACROLET ((B T)) (PROGN (LAMBDA (ARG) (IF A (IF B ARG (FOO ARG)) (BAR ARG))))) (SYMBOL-MACROLET ((B NIL)) (PROGN (LAMBDA (ARG) (IF A (IF B ARG (FOO ARG)) (BAR ARG)))))))) To be able to go into the code and conveniently disable this, we can define a no-hoist macro with the same syntax: (defmacro no-hoist ((&rest bool-vars) &body body) `(progn ,@body))
- carterschonwald 5y agofor some reason the page is unscrollable on firefox on my computer :(