I am trying to understand what are transducers - part 1
Tags: javascript
Published: 2023-10-18 11:47:42

This post constitutes my steps to understand what are transducers.

You can correct, and modify the code here: [Transducers](https://flems.io/#0=N4IgtglgJlA2CmIBcBWAHAOgAwHYA0IAZhAgM7IDaoAdgIZiJIgYAWALmLCAQMYD21NvEHIQIAL54a9RswBW5XgKEimAejUACAOIQAbsM21N-WAh5sIAzQHIAwjYA61ftVJtNdzQF5NFAIx4AEx4ACx4KHgAbAC6zs4amgCSpJoQHgAOfKSkEABGCJpsfEYZGbAAnppgAK6W5fBFAE60boR8TWC0lgKpCVoQ1JoCjQDmfHiaAO7pLHx1Jk3w3Y2DQp3wUBArqabmPW6aAPzx1IkA6izdRXx8sKlQJVONVwZGHvNNmlukWaS0sBuzVapHanSMJju+ys1Aw-U050aPFaNg8NVIjRsYJsmlgtwymjy8GR6NWHke8FS1D4HiWbBqTSGrSqegBNXgp0SABUrh4ELQoKl0UDSUUWI1nmZNABralTIYMNhzQWaDJNPh6aCbQlVJWNACCTRaVT4eTkxLYeHhdAYlU0SGqtAyk2IsHWkyWUBqPHgcOo8IAQgtntMSIDSLchhjGkrrkrso1FcqHnxKZpqbTKVlqFAgZ9IW42C01pNrvz3OmadMWLN5h4IwxHdQIBkarBujDSJytPrqBUprQKpMEDZUktkQS9RAvqKkKdXBXBjwAxUAMw+TQADx8AD4t5oANSaVcAbmcC48rvWAHkYBvt9499vNABSTRBHy+LBnly9es1MAACVNm9eAvl8AAKWgeB4SYeAZJZBAASl3IwYMPEwEOENhu00HlEydap4HjXNzz-NIXE2FceSWRpfDsDAugyCClxXVckJ-eEeQgVIrzAoiSLIwtVVoadNmvag7XojA+KaCDZNvKAONw-DNE9UCBOVISK1IACGCgAA1Nk02k9SfQgqCYLgrDkNQ6CeAw+CjWwpDcP1KU9QxTS+BVez4AyNhUmMPYLRhIxUmwpoIEpP1EjyBYBDtJijBzTRZLU4iGSZSEzFCgRYq0MzGjpLKIRqZsAEd2U0VlYHZP14SSQhpglVoPGKEwrkGMUE2BNwOi6A5SEmPUMq9H1vKgeFagrIkxUadsKxGCj5s60TYWcBAPB4LrqE2LkWjaAaO2sejnE0TRGKdFiXDY1yhku2T5JIG8YHui6MCKiDdKAkCfSad7NHhS4SAlRpdJgylQTbO0ixBMEwGGBkKPSbZARCiwYUmeFrmWHbNHcWhRkaPhmtGuH+s6E6hhDdIwJWYZsr2qYcuhfLGrJ8UliMbmuj7PrQWOoaUtzUaMYONJUgMJoqjyCBRnhUaMjAhHWgm2huageBRhaLWoFLVLRoYMAwA6KoFwAgKwqmOY21zObpaqGtRhYBqzi0AN4DBMY+EGUY0oZPUmmHYjNGFNViQgCaG0aDNOyMPI61WorJoKhEkVaESchSlHLABGrjKBYwU6THy04AMQ6CEfrG0CviVHjpnmWB7ZjcUC7qxosBdKvM4140C2RNh1upsVG6mZvW9W+AwACqp+8HPw4n9d28PbkviOVSWs4xXMbeuRvkVy3NjEcEAiqaM-4X1Wv-u3whysx6wZiVVb2jMPgZmof3clGOh6W5g6fUkwAyoX1FxduD8XAS2HtKNMbAJ481GABbCqRSbfAgIQQgYFsJFAqMrEWGUAFMiGPABADBBDDE5o0YgTQKxsHwRyVeGYazf1xFDSYLC-bVA6EwoGq8khDFGu-PEX9-bwE3PQBokwQwZFoNnUa1AAJEi+B+eRq1Bio3zrVdk2lyTzAKPAcu0FihRXzr4AIwQ8CrjCBEGIn0-rwAsvZSYOj4AoUfGhByAAqXwbjJhBGUivRIAAJHBLUd7T1ngwnmA91GjU0XnQEbi9FpXbGwQ0A8LGBBCH4SImhYiTBwPYr6llYId3ZB4vc9kMCuCHhBNxSFJgUBiEE+EAAZYio4CyWCUSTZGchPh7QqPCCSjQqqUglhrHi8Ae5fFbNzJyVhcgMMmI3dIqpsi5EMYrEoEiI7Z2Sq0XM6V0TcMSrqdejjJrHH6J0tg3SixVDnMErQ4pYDK0vr+YSdTriQVoJMPIVSjC1IEPUoF85yJMXOLMYC406IB2gWFeSj8ULAHOkQ0qZTrLOVsp4rxoKXDdBRS4CCTlEJsCQkE8QuFoWwuubAtMxgoFPxIbmEqjIIQXzTgAOSjrMiJyIhHiiGHI7O+ZmZ2gvkCUaG9BKr3QfmcWMI073LDrsJYKw5maAkVIhAkxahuhbHaAEgJRpkJntheEirkbKusHkKoKBUmGvqLAaKUAVwoA3AxL6dKlRwtAhBB8T5NDeM0CgJpS82mvM0Gqw+mqhBcuudLXI1h0HCJevxUuU1vkVlkjC-11zIIRy2EPdxqF0UPUxZy7FmFcWUtQiWqOKwyU2QbQAMnbQS35bBW31pQgAHwHV4n8NLV73O6TwBNjRjnqpnUMHyJzM1fIvMMGARlO6pFMo456bowIFpYAG8y+5PHbjfB+bwX5I0tPurha8yMI6anmKkCmgsqYSyFZWFmc1aKbgObvXEEA4EEz4C81dhrPX3lQtuMNKAfyrp4opDcJ6Q3ns-Job8qSBS5kgpuSYFRgXbiPCMle4G2yeqPfxXwfrD07ogxUCNqTF2UfAmlZdB7KMsVIIpW9Lhdr7UOm+waYUzoPQcfCiC9GUAseaa0jF4nA3McccHKN8mvrYcmFgQGozkZdG6mqU05Dt7uDDJWTMEZYAGH1oSUOIYNYk2Fa1CobtEiCKRvXQTqsDgjS5jO7mSpaIVPgVcIYn7WQy3tPCAAtKtO1Qw7DReTspzQknyMMZk2uqAGXsP3USDFhJzY2AbuqhBbuUaQ4PN2KatIHhRxCAyE4VeMWH5NCDqbbmF8grcwzJCWe2RaCGJ8-AXUtBgMIJKHIlog0wKpG6pFeeqUOXZVyN-QoKSY2IlDFKaMK1FESMyNkDw+9tp8D6-8QxiLWWkD9BdDpXTUjlEXi-Fg80vJanUbOnbNtwmxj5MsQUGBAd3cq+qxYyxE0ZroZeR+MDeS9bTN1SAOYKug6PoCDZqJBPwqaDiTaodX3Y43GSqEeVqAemU5MAm9XgVxYU+ZC+kx3D+WjRcDOQwlhTCihDmsqQ3XAYjJFwQWO64bji6haVnimcEnxbTr6DOqfM84qvMJ3NG6tBpPxAcuonhc7JILgnIvfAS73MT3KrLGfU9QrLnd8upcs60BO4U+z2zdTdWwdYpqqjHe3vmCm2PGog+ZTD62NZ8aMqCrffi6jJsyHWIQpbEI5Z0Aiyy7zl2JY2yji98P8IiiIJj4qGbGCsE4MoQw5W13cJJDHtQaUmgKjzE0K8MY7Icjal+2PVISeNZVFT2FdZQxCAmKTYTgAhOPxqOZ4CbDWe1Ub8D88a1j0X9BWwS8UrwQQqCm+SbNQXkOCE5fd-DDNBaFCs6E-GCP1Q2Jg4048m6N03VFhYbty1sQQrYV0FX+F-9FzWhNtP0DMag4Aqh-hnlr4BZCc1d08woO9w8R8RcL9MpOVi4KczNWF-YyBhoMDuF2tGhuAQAMQ2Y3BRAsAkAsAot-BVxyD-AsAsAJApAQAbRZBakchCDXAVA2BRAJAYhxAgA)

```js
// Given a collection 'C'
const C = [1,2,4,5,6]

// Is it possible to apply mutiple transformations 
// in one go, without create intermediates collections ?

// What tools do we have at our disposal to transform a collection.
// We can't use 'for' loop because it does not return any value

// That leads us to use the well known methods provided by the Array object,
// namely : map, filter, reduce.

// But we will soon see that those methods does not respond to our constraint, at least not whithout some manipulations

// Anyway, le's recap their use :

const incBy3 = x => x + 3;
const filterOdd = x => x  % 2 == 0;
const sumReducer = (acc, current) => acc + current

// The map method 
const incedByThree = C.map(incBy3);

// This filter method
const pairedOnly = C.filter(filterOdd);

// The reduce method
const summedValues = C.reduce((acc, current) => acc + current)

// All these methods accepts a collection as entries.
// but only map and filter return a collection.
// reduce return a unique value.

// If we want to chain those transormations, the reduce method
// must be the last one in the chain.
let chainedTransformation = C
  .map(incBy3)
  .filter(filterOdd)
  .reduce(sumReducer)
  
// While we successfully transform our initial collection, 
// at each stage of the transormation we iterate on a new collection.
// If there are many transformations and the collection is very big
// the performance are degraded, and the memmory consumption whould be very high.

// Before going further, let us precice some notions about the reduce method.
// We can pass an initial value to a reduce method.
// For a sum reducer this would be the value 0, for an array concataination this would be the empty array []

// The reduce method is passed what is called a "reducer"
// A reducer is function with the following signature : A, B => A
// The function takes two arguments of different type and return an element of the first type
// nothing less, nothing more
 
// In the following example, we pass the number 2 as the initial value
const doubleFactorial = [1,2,3,4,5].reduce((acc, value) => acc *= value, 2);

// Here we pass the empty array as the initial value
const flatArray = [1,2, [5, 6], 7].reduce((acc, value) => acc.concat(value), []);

// Let's continue our journey
// One question arise, for pure curiosity, is it possible
// to express map and filter using only the reduce method ?
//Let's try :

// helper
const concat = (a, b) => a.concat(b)

const mapWithReduce = function (func) {
  return (acc, current) =>  acc.concat(func(current));
}

// mapWithReduce takes a function and return a reducer.
// Nice, we can then pass our newly reducer to the reduce method
// of our collection.
// Let us create, for example, multiply all the element
// of our collection by 5
const multipliedBy5 = C.reduce(mapWithReduce(x => x * 5), []);


// Let is create a reduce version of the filter method
const filterWithReduce = (predicate) => {
   return (acc, current) => predicate(current) && acc.concat(current) || acc;
}
// Let's create and use an odd filter
const oddValues = C.reduce(filterWithReduce( x => x % 2 == 0), [])


// Our previous transformation can now be reexpressed like so:
const mulBy5 = x => x * 5;
const isOdd =  x => x % 2 == 0;
const add = (x, y) => x + y

const mulBy5Reducer = mapWithReduce(mulBy5)
const oddReducer = filterWithReduce(isOdd)

chainedTransformation = C
  .reduce(mulBy5Reducer, [])
  .reduce(oddReducer, [])
  .reduce(add, 0)
  
// Our main problem is still not resolved, bet we are on the way.

// In our transformation, there are three values than can vary :
// - the collection C
// - the reducer (mulBy5Reducer, oddReducer, add)
// - the initValue (0, []), let's call it 'step'
// - furthermore reducers are not composable, they take two paramaters in entry and return a single value

// We will see in the next post what composable functions.
  
// Let's play with these ideas and see where that leads...
// Let's us create the first function that comes in mind, let us call it 'transducer' 
let transducer = (collection, reducer,  step) => collection.reduce(reducer, step);

// We can rewrite this like so :
transducer = collection => reducer => step =>  collection.reduce(reducer, step);

// Here is anoter way to write it :
transducer = reducer => (collection, step) => collection.reduce(reducer, step);

// Let'us explain litterally what is our tranducer
// It's a function which takes a reducer as parameter and return a binary function, function which takes
//  two parameters different types.

// I think you have guessed that this binary function is in fact a reducer !!!
// Indeed, it takes two parameters of different type (a type of array, a type of object) and return a type of array.
// That's exactly the definition of a transducer.

// We can proudly say :
// A transducer is a function that takes a reducer and return a reducer, nothing less, nothing more 
 
```

So, ma comprehension till now is :

**A transducer is a function that takes a reducer and return a reducer.**


Don't miss the next post.