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