Transducers are composable transformations of reducing functions. They provide a way to implement high-order operations such as
drop in a way that they are independent of the collection they operate on. This way, these operations are defined only once, for all collections in Yona, specifically for
Dict and in fact, they can be used for custom user-built data collections, provided that it exposes a
Transducer constructor is a function that takes a transducer as an argument and returns a new transducer.
Using a transducer¶
Transducer needs to be used in a combination with
reduce function, best seen in an example, a sequence can be filtered like this:
let transducer = Transducers::filter \val -> val < 0 (0, \acc val -> acc + val, \acc -> acc * 2) in Seq::reducer [-2,-1,0,1,2] transducer
What this code does, is that it calls function
Seq::reducer with two arguments:
- sequence to reduce
And the transducer is constructed by function
Transducers::filter, which takes two arguments:
- predicate - function to filter elements added to the resulting collection
The second argument here is another transducer actually. This is how transducers are composed. Transducer can either be created by using a predefined one in the
Transducers module, or created manually as a tripple, as described in the next section.
Implementing a transducer¶
Transducer in Yona is a tripple, with following elements:
- initial state - is the initial state of the accumulator of the step function
- step function - is a function of two arguments - accumulator and an element, returning a new state of the accumulator
- complete function - is a function of one argument - the final state of the accumulator, returning the final value of the
# pred: function of one argument (element) returning boolean value # init: initial state # step: function of two arguments (accumulator, element) returning new value of the accumulator # complete: function of one argument (final state of accumulator) returning final return value filter pred (init, step, complete) = let new_step = \acc val -> if pred val then step acc val else acc in (init, new_step, complete)
Source code for all transducers available in Yona is available here.
Note that transducers are actually used in generators as well, they are just a syntax sugar for them for the built-in collections.