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 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/f1ada73f-8249-431a-9f4d-580aea12bdefn%40googlegroups.com.

Reply via email to