Frequently I want to use reductions
only to quickly realize that I'm not interested in the successive values of the state.
A simple example is to imagine one wants to increment a number represented by a sequence of its binary digits:
(inc '()) is (1)
(inc '(1)) is (0 1) ; yes the list is inversed, the lowest significant bit is the first item
(inc '(0 1)) is (1 1)
The essence of the computation is simple, this is this function:
(fn [c d] ; c for carry, d for digit
; returns [new-carry incremented-digit]
(case [c d]
[1 1] [1 0]
[0 0] [0 0]
[0 1])) ; all remaining cases
Not captured by this function is the fact that at the end of the number we want to "flush" the carry: append one more item if the carry is one.
Go ahead, try and implement increment
with reductions
! I would be delighted to see an elegant solution.
So, this is a iteration pattern that I have struggled with on numerous occasions, hence I propose the below carry
function to express it.
(defn inc-digit
([] 1)
([c] (case c 1 [1] nil))
([c d]
(case [c d]
[1 1] [1 0]
[0 0] [0 0]
[0 1])))
=> (take 10 (iterate #(carry inc-digit %) ()))
(() (1) (0 1) (1 1) (0 0 1) (1 0 1) (0 1 1) (1 1 1) (0 0 0 1) (1 0 0 1))
Have you already encountered this pattern too? Does it have a name? Am I oblivious to a simpler expression?
I'm surprised you didn't mention transducers.
inc-digit
is a stateful process producing an arbitrary number of output values when it's fed with an input value, so my knee-jerk reaction would be to write a transducer here :And then
carry
would besequence
:IMO what you have here is an alternative representation of transducers, a purely functional one where state is made explicit. In the general case, you can convert an arbitrary carry function to a transducer :
Note that converting the other way round is not possible, because transducers encapsulate their state.