Hello Chickeneers, find attached a suggested addition to miscmacros: the thrush operator family. Apparently it stems from Raymond Smullyan's book on combinatorial logic "To Mock a Mockingbird", which I haven't read (yet). I've first learned about it through Clojure and have found it quite nice for increasing the readability of chained calls. See Debasish Ghosh's post [1] about it for some background.
As a practical example, consider this code: (write (fold + 0 (map (lambda (i) (* 2 i)) (iota 10)))) Using the thrush operator it can be written like this: (->> (iota 10) (map (lambda (i) (* 2 i))) (fold + 0) (write)) which basically expands to the expression above, i.e. it inserts each expression as the last argument of the following expression. I find it much easier to read though since the order of evaluation is the order of appearance in the code. I like to think of it like `let*' as opposed to nested `lambda': ((lambda (x) ((lambda (y) ((lambda (z) (+ x y z)) 3)) 2)) 1) versus: (let* ((x 1) (y 2) (z 3)) (+ x y z)) Much easier to track what's going on there as stuff that belongs together is visually close to each other. There's also `->' which inserts each expression as the first argument of the following one. The difference: (->> 10 (- 3)) ; => -7 (-> 10 (- 3)) ; => 7 For kicks and fun I also added starred versions (`->*' and `->>*') which are multi-value aware. Not sure how useful that is and I didn't want to add it to the default macros to avoid the overhead. But it's good to have them just for completeness sake! I guess that's about it. I'm not sure if adding it to miscmacros is a great idea, might as well just create a `thrush' egg. OTOH we have the similar `doto' macro in there already. Comments? Moritz [1] http://debasishg.blogspot.com/2010/04/thrush-in-clojure.html
Index: miscmacros.scm =================================================================== --- miscmacros.scm (revision 25904) +++ miscmacros.scm (working copy) @@ -9,13 +9,14 @@ define-optionals define-parameter define-enum ignore-values ignore-errors ecase - define-syntax-rule) + define-syntax-rule + -> ->* ->> ->>*) (import scheme) ;; No effect -- caller must import these manually. (import (only chicken when unless handle-exceptions let-optionals make-parameter - add1 sub1)) + add1 sub1 define-for-syntax)) ;;; Modify locations, T-like: @@ -303,4 +304,55 @@ clauses ... (else (error "no valid case" val)))) +(define-for-syntax (expand-thrush x weave) + (let loop ((y (cdr x)) (form (car x))) + (if (null? y) + form + (let ((z (car y))) + (loop (cdr y) + (weave z form)))))) + +(define-syntax -> + (ir-macro-transformer + (lambda (x i c) + (expand-thrush + (cdr x) + (lambda (z form) + (cons (car z) + (cons form (cdr z)))))))) + +(define-syntax ->* + (ir-macro-transformer + (lambda (x i c) + (expand-thrush + (cdr x) + (lambda (z form) + `(receive args ,form + (apply + ,(car z) + (append args (list . ,(cdr z)))))))))) + +(define-syntax ->> + (ir-macro-transformer + (lambda (x i c) + (expand-thrush + (cdr x) + (lambda (z form) + (append z (list form))))))) + +(define-syntax ->>* + (ir-macro-transformer + (lambda (x i c) + (expand-thrush + (cdr x) + (lambda (z form) + `(receive args ,form + (apply + ,(car z) + (append (list . ,(cdr z)) args)))))))) + ) + + + + Index: tests/run.scm =================================================================== --- tests/run.scm (revision 0) +++ tests/run.scm (working copy) @@ -0,0 +1,22 @@ +(use test srfi-1 miscmacros) + +(test 1 (-> 99 (/ 11) (/ 9))) + +(test '(1 2 3 4) + (->* (values 1 2) + (list 3) + (append '(4)))) + +(test 7 (-> 10 (- 3))) +(test -7 (->> 10 (- 3))) + +(test 9 (->> 1 (+ 2) (* 3))) + +(test 9 (->> '(1 2 3) + (map add1) + (fold + 0))) + +(test '((foo . 100) (bar . 200)) + (->>* (values '(foo bar) '(100 200)) + (map cons))) +
_______________________________________________ Chicken-hackers mailing list Chicken-hackers@nongnu.org https://lists.nongnu.org/mailman/listinfo/chicken-hackers