weavejester / medley

A lightweight library of useful Clojure functions
Eclipse Public License 1.0
870 stars 67 forks source link

Function request: join #29

Closed Engelberg closed 5 years ago

Engelberg commented 6 years ago

I recently ran into a performance problem due to (apply concat ...) not being sufficiently lazy. Turns out, this has been a known issue for 4+ years. https://dev.clojure.org/jira/browse/CLJ-1218 and https://dev.clojure.org/jira/browse/CLJ-1583.

In the comments, it was pointed out that these problems could be avoided by just using a function called join that operates directly on a sequence of sequences.

(defn join
  "Lazily concatenates a sequence-of-sequences into a flat sequence."
  [s]
  (lazy-seq
   (when-let [s (seq s)] 
     (concat (first s) (join (rest s))))))

Given that this has been an issue for several years, I was wondering if you might consider inclusion of this join function into medley. Frankly, even if concat's behavior were eventually fixed in a future version of Clojure, I use (apply concat ...) so frequently that I'd like to have join as a convenient replacement for that pattern anyway.

cloojure commented 6 years ago

I have added this to the Tupelo library https://github.com/cloojure/tupelo as tupelo.lazy/join:

API docs: http://cloojure.github.io/doc/tupelo/tupelo.lazy.html

source:

 (defn join
   "Lazily concatenates a sequence-of-sequences into a flat sequence."
   [sequences]
   (lazy-seq
     (when-let [curr-seq (seq sequences)]
       (concat (first curr-seq) (join (rest curr-seq))))))

with tests:

(dotest (is= [] (lazy/join [[]])) (is= [1] (lazy/join [[1]])) (is= [1 2 3 ] (lazy/join [[1] [2 3]])) (is= [1 2 3 4 5 6] (lazy/join [[1] [2 3] [4 5 6]])) (is= [1 2 3 4 5 6] (lazy/join [[] [1] [] [2 3] [4 5 6] []])))

On Wed, Jul 18, 2018 at 1:36 AM, Mark Engelberg notifications@github.com wrote:

I recently ran into a performance problem due to (apply concat ...) not being sufficiently lazy. Turns out, this has been a known issue for 4+ years. https://dev.clojure.org/jira/browse/CLJ-1218 and https://dev.clojure.org/jira/browse/CLJ-1583.

In the comments, it was pointed out that these problems could be avoided by just using a function called join that operates directly on a sequence of sequences.

(defn join "Lazily concatenates a sequence-of-sequences into a flat sequence." [s] (lazy-seq (when-let [s (seq s)] (concat (first s) (join (rest s))))))

Given that this has been an issue for several years, I was wondering if you might consider inclusion of this join function into medley. Frankly, even if concat's behavior were eventually fixed in a future version of Clojure, I use (apply concat ...) so frequently that I'd like to have join as a convenient replacement for that pattern anyway.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/weavejester/medley/issues/29, or mute the thread https://github.com/notifications/unsubscribe-auth/AGwXB3SlrYqmuXaiI0eJeFWskI8lelyhks5uHvOjgaJpZM4VULCY .

weavejester commented 6 years ago

This looks reasonable.