1

Is it possible to create a ref with a transducer in Clojure, in a way analogous to creating a chan with a transducer?

i.e., when you create a chan with a transducer, it filters/maps all the inputs into the outputs.

I'd expect there's also a way to create a ref such that whatever you set, it can either ignore or modify the input. Is this possible to do?

lobsterism
  • 3,469
  • 2
  • 22
  • 36

2 Answers2

2

Adding a transducer to a channel modifies the contents as they pass through, which is roughly analogous to adding a watch to a ref that applies it's own change each time the value changes. This change it's self then triggers the watch again so be careful not to blow the stack if they are recursive.

user> (def r (ref 0))
#'user/r
user> (add-watch r :label
                 (fn [label the-ref old-state new-state]
                   (println "adding that little something extra")
                   (if (< old-state 10) (dosync (commute the-ref inc)))))
#<Ref@1af618c2: 0>
user> (dosync (alter r inc))
adding that little something extra
adding that little something extra
adding that little something extra
adding that little something extra
adding that little something extra
adding that little something extra
adding that little something extra
adding that little something extra
adding that little something extra
adding that little something extra
adding that little something extra
1
user> @r
11

You could even apply a transducer to the state of the atom if you wanted.

Arthur Ulfeldt
  • 90,827
  • 27
  • 201
  • 284
1

This is an interesting idea, but the wrong way to go about it for at least a couple reasons. You'd lose some relationships you'd expect to hold:

(alter r identity) =/= r

(alter r f)(alter r f) =/= (alter r (comp f f))

(alter r f) =/= (ref-set r (f @r))

Also some transducers are side-effecting volatiles, and have no business in a dosync block. i.e. if you use (take n) as your transducer then if your dosync fails, then it'll retry as though invoked with (take (dec n)), which violates dosync body requirements.

The problem is a ref lets you read and write as separate steps. If instead there was something foundational that let you "apply" an input to a hidden "state" and collect the output all in one step, consistently with the STM, then that'd be something to work with.

lobsterism
  • 3,469
  • 2
  • 22
  • 36