Last active
April 27, 2017 13:39
-
-
Save cemerick/6803d53a541d68e7303d68587e952261 to your computer and use it in GitHub Desktop.
reduce-for: easier-to-understand nested reductions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; a toy example of a nested reduction; especially when function bodies are nontrivial, or when the nesting | |
; gets much deeper than 2 levels, it's easy to lose track of which values are being reduced over at each | |
; level, etc | |
(let [x {:a [1 2 3] :b [4 5 6]}] | |
(reduce | |
(fn [x [k vs]] | |
(reduce | |
(fn [x v] (update x :sum (fnil + 0) v)) | |
x | |
(map inc vs)) | |
x | |
x)) | |
=> {:a [1 2 3], :b [4 5 6], :sum 27} | |
(defmacro reduce-for [v steps & body] | |
(if (empty? steps) | |
`(do ~@body) | |
`(reduce | |
(fn [~v ~(first steps)] | |
(reduce-for ~v ~(drop 2 steps) ~@body)) | |
~v | |
~(second steps)))) | |
=> #'user/reduce-for | |
; reduce-for provides a for-like syntax for defining each step of the nested reduction, | |
; so they're all kept together. The `body` of the `reduce-for` becomes the innermost | |
; reduce's body | |
(let [x {:a [1 2 3] :b [4 5 6]}] | |
(reduce-for x [[k vs] x | |
v (map inc vs)] | |
(update x :sum (fnil + 0) v))) | |
=> {:a [1 2 3], :b [4 5 6], :sum 27} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment