Skip to content

Instantly share code, notes, and snippets.

@aamedina
Last active December 20, 2015 21:19
Show Gist options
  • Select an option

  • Save aamedina/6196869 to your computer and use it in GitHub Desktop.

Select an option

Save aamedina/6196869 to your computer and use it in GitHub Desktop.
;; So now you have a feel for when you can preserve the essence of some function or procedure, even when it appears different at first glance.
;; Now we are finally ready to understand Stream Fusion.
;; Streams are a "Type" of sequential collection that may be useful for "unrolling" complex list operations into
;; a list which is structurally equivalent, but much faster to execute.
;; consider the following
(->> (map squared (range 100))
(filter even?)
(remove prime?)
(map str))
;; The ->> macro is a Clojure macro that allows us to "thread" the result of the expression into the second argument
;; of the following expression. So you can think of it like this...
(->> (0 1 4 9 16...) ;; these are the squared results of the mapping function
(0 4 16...) ;; result of filtering out evens
(0 4 16...) ;; no primes here, we only have evens and there's no two! :)
("0" "4" "16"...)) ;; and finally, the result.
;; the big idea behind stream fusion is what if we could have a function that, at compile time, (so let's say a macro)
(defmacro fusion
[& exprs]
;; does magical compile time fusion on the streams here
)
;; the result of which, when writing code that looks like this...
(def my-stream (stream (range 100)))
;; would be unrolled by the fusion macro to produce something like
;; compiled source
;; ie
(fusion
(->> my-stream
(filter even?)
(remove prime?)
(map str)))
;; would become one function which is equivalent to the following
(comp (partial map str) (partial remove prime?) (partial filter even?))
;; now this is conceptually what stream fusion does conceptually, but where is the optimization in this composition?
;; The idea is that since the composition of these functions is possible and any function followed by the dual operation
;;, where the dual is the equivalent function in the opposite category, for example, fold and unfold for Lists,
;; for streams these dual operations are stream and unstream.
;; instead of converting between streams and lists on every application of the function as so
(stream (filter even? (unstream my-stream)))
;; which is clearly inefficient by any definition, since you must stream and unstream on the application of every function,
;; function composition and the duality property of the stream and unstream functions allow us to conceptually do the following instead
(->> (unstream (my-stream))
(comp (partial map str) (partial remove prime?) (partial filter even?))
(stream))
;; so the conversion from stream to list back to stream is only done once.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment