[ANN] Reducers, a better way to fold

36 views
Skip to first unread message

Jack Firth

unread,
Jul 15, 2019, 9:37:52 PM7/15/19
to Racket Users
I've recently added another library to Rebellion, this one for reducers. A reducer is a way to combine a series of values:


> (require rebellion/streaming/reducer)
> (reduce into-sum 1 2 3 4 5)
15


You can reduce any sequence using `reduce-all`:


> (reduce-all into-product (in-range 1 20))
121645100408832000


You can make a reducer from any fold:


> (define into-reversed-list (make-fold-reducer (lambda (lst v) (cons v lst)) '()))
> (reduce-all into-reversed-list (in-range 1 10)
'(9 8 7 6 5 4 3 2 1)


You can use `for/reducer` and `for*/reducer` to fold over any `for`-loop using a reducer:


> (for/reducer into-reversed-list
               ([n (in-range 2 20)]
                #:when (prime? n))
    n)
'(19 17 13 11 7 5 3 2)


And you can implement your own `for/...` macros using a reducer:


> (define-syntaxes (for/reversed-list for*/reversed-list)
    (make-reducer-based-for-comprehensions #'into-reversed-list))
> (for/reversed-list ([n (in-range 2 20)]
                      #:when (prime? n))
    n)
'(19 17 13 11 7 5 3 2)


Folds are only the most basic type of reducer: not all reducers are as simple as a plain fold. Reducers can use hidden mutable state to make reduction performant, and reducers can short-circuit and return a result without iterating through the entire sequence. See the rebellion/streaming/reducer documentation for more details, as well as instructions on how to make your own reducers. To use, install Rebellion with `raco pkg install rebellion` and import the reducers library with `(require rebellion/streaming/reducer)`.

This library is currently in an experimental alpha state. I might break your code. Warn me before seriously depending on this, especially if you won't be using it in an open-source package in the package catalog (where the package build server can alert me if I break you).
Reply all
Reply to author
Forward
0 new messages