Very nearly a direct hit :-) 'reductions' definitely gives me what I want when dealing with eager and lazy sequences ... but... it seems to have escaped the transducer makeover :-(
core> (reductions + 0 [1 2 3 4 5]) (0 1 3 6 10 15) core> (take 6 (reductions + (range))) (0 1 3 6 10 15) core> (reductions + 0) Error printing return value (IllegalArgumentException) at clojure.lang.RT/seqFrom (RT.java:557). Don't know how to create ISeq from: java.lang.Long core> (reductions +) Execution error (ArityException) at theremin.core/eval351732 (form-init6069347464735150015.clj:60). Wrong number of args (1) passed to: clojure.core/reductions core> at least I now know what to call what I am looking for. Thanks for your help - much appreciated, Jules On Sunday, 27 November 2022 at 23:47:22 UTC sritc...@gmail.com wrote: > Pretty sure what you’re looking for is either > https://clojuredocs.org/clojure.core/reductions or something close. This > idea is called a “scanLeft” in some functional languages, so that should > give you another search term to use. Good luck! > > On Sun, Nov 27, 2022, at 12:00 PM, Jules wrote: > > Guys, > > I've found myself needing a function that I am sure cannot be an original > but I'm not aware of it existing anywhere... > > It is a cross between 'map', 'reduce' and 'iterate'... > > Given a function 'f' and a sequence 's' it would return you a sequence of > : > ``` > [(f s[0]) (f (f s[0]) s[1]) (f (f (f s[0]) s[1]) s[2]) ...] > ``` > > or, more concretely, e.g.: > ``` > util-test> (stateful-map + [0 1 2 3 4 5]) > [0 1 3 6 10 15] > util-test> > ``` > > I have a couple of approaches to it - one using reduce: > > ``` > (defn stateful-map-1 [f [h & t]] > (reduce > (fn [acc v] > (conj acc (f (last acc) v))) > [h] > t)) > ``` > > and another, mapping using a stateful function: > > ``` > (let [secret (Object.)] > (defn stateful-mapper [f] > (let [state (volatile! secret)] (fn [v] (vswap! state (fn [old new] > (if (= secret old) (f new) (f old new))) v))))) > > (defn stateful-map-2 [f s] > (mapv (stateful-mapper f) s)) > ``` > > The former feels more idiomatic whereas the latter (although uglier) is > more efficient and has the added benefit of being able to be used for > general map-ing which is important as I want to use this approach to > transduce a clojure.async.channel. > > It could, of course, be expressed directly as a transducer but it feels > like something simpler that should only be lifted to a transducer as and > when needed (see test below) ... > > Here is my working testsuite: > > ``` > (deftest stateful-map-test > (testing "reduction" > (is > (= > [0 1 3 6 10 15] > (stateful-map-1 + [0 1 2 3 4 5])))) > (testing "mapping stateful function" > (is > (= > [0 1 3 6 10 15] > (stateful-map-2 + [0 1 2 3 4 5])))) > (testing "transduction" > (is > (= > [0 1 3 6 10 15] > (sequence (map (stateful-mapper +)) [0 1 2 3 4 5]))))) > ``` > > Am I missing a standard way of doing this in Clojure ? Or is a stateful > function the best answer ? > > Interested in your thoughts, > > > Jules > > > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clo...@googlegroups.com > Note that posts from new members are moderated - please be patient with > your first post. > To unsubscribe from this group, send email to > clojure+u...@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/clojure?hl=en > --- > You received this message because you are subscribed to the Google Groups > "Clojure" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to clojure+u...@googlegroups.com. > To view this discussion on the web visit > https://groups.google.com/d/msgid/clojure/f1ada73f-8249-431a-9f4d-580aea12bdefn%40googlegroups.com > > <https://groups.google.com/d/msgid/clojure/f1ada73f-8249-431a-9f4d-580aea12bdefn%40googlegroups.com?utm_medium=email&utm_source=footer> > . > > > -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/clojure/4c2bf7c2-2703-4d4a-9cc0-00cc830d2705n%40googlegroups.com.