jackfirth / rebellion

A collection of core libraries for Racket
https://pkgs.racket-lang.org/package/rebellion
Apache License 2.0
80 stars 15 forks source link

Static transducer fusion #358

Open jackfirth opened 4 years ago

jackfirth commented 4 years ago

These two transducer pipelines should have the exact same performance:

(transduce some-sequence
           (mapping f)
           (taking 20)
           (mapping g)
           (taking 5)
           (append-mapping h)
           (filtering p)
           (filtering q)
           #:into some-reducer)

(transduce some-sequence
           (taking 5)
           (append-mapping (compose1 h g f))
           (filtering (conjoin p q))
           #:into some-reducer)

That is, there should be rules for statically fusing transducers, similar to how for forms will specially recognize the various in-list and in-vector forms. Any function that accepts a chain of transducers, such as transduce and transducer-compose (#191), should be wrapped in a macro that looks for fusion opportunities. There are two primary performance benefits:

Alternatives considered

There could be some sort of protocol for dynamic transducer fusion, using generic interfaces. The upside is that this kind of code could still trigger fusion:

(define (adding x)
  (mapping (lambda (y) (+ x y))))

(transduce some-sequence (mapping f) (adding 10) (mapping g) #:into into-list)

However, the downsides are significant:

jackfirth commented 4 years ago

Note: should probably gather together references to prior art here. Stream fusion is a very widely studied problem: