<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><atom:link href="https://www.api.antoniodiaz.me:443/api/v1/en/xml/rss" rel="self" type="application/rss+xml"/><title>Antonio Díaz - Personal website</title><link>https://www.api.antoniodiaz.me:443</link><description>Software and design</description><language>en-EN</language><item><title>Functional JavaScript: basic concepts</title><pubDate>Wed, 21 Jan 1970 00:00:00 GMT</pubDate><guid isPermaLink="true">https://www.antoniodiaz.me/en/blog/12</guid><description><![CDATA[<p><p>I am going to start a series of introductory articles about functional programming. We will address this subject as a kind of notes for newcomers, but also as notes for my future self. The goal won&#39;t be to cover exhaustively everything related to functional programming, but to provide some concepts and basic operations on which this paradigm is based.</p><p>Functional programming is built on some common operations, as composition and partial application, leading to some quite specialized techniques, as the transducers. Its goal is to minimize the shared states living within our applications as well as producing more declarative code —and therefore more legible— and, finally, allowing modules easier to test.</p><p>For this series we are going to use a common language: JavaScript. This is a language that works well with functional programming, although it was not purely conceinved for it as Erlang or Haskell. Because of this we will have to implement some structures and operations that other languages may provide natively, </p><p>As we will be covering functional programming in a concise way here, for those looking for a more exhaustive approach I recommend two resources:</p><ul><li>Professor Fisby&#39;s Mostly Adequate Guide to Functional Programming, Brian Lonsdorf, 2021: <a href="https://mostly-adequate.gitbook.io/mostly-adequate-guide" target="_blank"><em>https://mostly-adequate.gitbook.io/mostly-adequate-guide</em></a>.</li><li>Funcional Light Javascript, Kyle Simpson, 2017: <a href="https://github.com/getify/Functional-Light-JS/tree/master" target="_blank"><em>https://github.com/getify/Functional-Light-JS/tree/master</em></a>.</li></ul><p>In this first article we are going to discuss the most basic concepts and operations that we can find in functional programming. We will talk about:</p><ul><li>Immutability</li><li>Purity</li><li>Arity</li><li>Currying</li><li>Partial application</li><li>Point-free style</li><li>Compose and pipe</li><li>Eager and lazy evaluation</li></ul><p>We&#39;ll go over each of these concepts, presenting easy examples in JavaScript to keep things as straightforward as possible.</p><h1>Immutability</h1><p>One of the main challenges we may encounter in programming is shared state.</p><p>Let’s say we are working with JavaScript and have an object with a property <mark>a</mark>, stored in memory in the variable <mark>x</mark> with a certain value. If we then copy <mark>x</mark> into a new variable <mark>y</mark> what we are actually copying is the reference to <mark>x</mark> in <mark>y</mark>. From this point forward, any changes made to <mark>y</mark> will also affect <mark>x</mark>.</p><p>As you can imagine, this can be problematic, as it may lead to unexpected and imperceptible modifications to <mark>x</mark>.</p><pre><code>language-javascript<br />⁠<br />const sherlock = { name: &quot;Sherlock&quot; };<br />⁠const bilbo = sherlock;<br />⁠bilbo.name = &quot;Bilbo&quot;;<br />⁠⁠console.log(sherlock); // { name: &quot;Bilbo&quot; }</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;target=99&amp;jsx=0&amp;module=1&amp;ts=4.0.2#code/MYewdgzgLgBBAWBTATgGxMA1jAvDA3jGAIYC2iAXDAEQDKSaGm1MAvgNwBQoksARgEtUfELjgN0WLoOEgAdCXJjqAISEjqXHhBCpEc9AHMAFAhSTMASnYwA9LYJEylGmtktWQA" target="_blank">Playground</a>&nbsp;</figcaption><p>To address this issue we may use the spread operator <mark>...</mark> to extract the properties from <mark>john</mark> when creating a new object <mark>bob</mark>:</p><pre><code>language-javascript<br /><br />const sherlock = { name: &quot;Sherlock&quot; };<br />⁠const bilbo = { ...sherlock };<br />⁠bilbo.name = &quot;Bilbo&quot;;<br />⁠sherlock.name = &quot;Sherlock&quot;;<br />⁠console.log(sherlock); // { name: &quot;Sherlock&quot; }</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;target=99&amp;jsx=0&amp;module=1&amp;ts=4.0.2#code/MYewdgzgLgBBAWBTATgGxMA1jAvDA3jGAIYC2iAXDAEQDKSaGm1MAvgNwBQoksARgEtUfELgIwAdFIQp0WNl0HCQEkuTHUAQkJHUuMxllVlEG+rKZ7u4CCFSIJ6AOYAKA3MwBKdjAD0v8TVKGnNDZjYgA" target="_blank">Playground</a>&nbsp;</figcaption><p>Keep in mind that the spread operator copies the first-level properties of an object by value, but nested properties are copied by reference <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;target=1&amp;jsx=0&amp;module=1&amp;ts=4.0.2#code/MYewdgzgLgBBAWBTATgGxMA1jAvDA3gFAwxgCGAtogFwwBEAykmhpnQDTExkAmPyiCBFr44UAYii06AJhkBGAEIxFZTChgNxiSRxgAHVGWA16AGXA9wdGAF9OtgNyFQkWACMAlqnchcBGAA6YIQUdCw7Zy8fEEDyKn86RW9fOiiU2N5+QQhA6AlYPCSyAHMYAFEwHjTCaN9ArIEhQMNjRESACRB3LyhrZxdwCBBURED0EoAKOtj49pwF+mSYugBKRxgAek2YcQBXREHIEbGJ6YyGvibc-J1CxeKyyur1rZ39w9dh0fGQKZnLtlmq0TLgHl0ep4+mA1httrtkAdCEdvqc-pNQiwsHFKPMHpjwmxXvCPiiTr8pgTWIDrnltJIwUU5EoVGoNFoCrC3jAAGZkVAQdqAGXIyT8zlTsY0ci0jKCFkULFVrMSdnyBcLCEA" target="_blank">with shallow copy</a>. To avoid this issue, we can use the methods provided by the JSON object.</p><p>Another example of the problem with shared states could arise when dealing with concurrent operations. In this case, we have an increment operation whose result is stored in a <mark>sharedState</mark> object. But we also have a <mark>decrement</mark> operation that calculates a new value, which is also saved in <mark>sharedState</mark>. The result is a shared state: <mark>sharedState</mark> refers to both the value produced by <mark>increment</mark> and the one from <mark>decrement</mark>. Considering that both operations are impure, we end up with code that is hard to follow and difficult to test.</p><pre><code>language-javascript<br /><br />const sharedState = { type: &quot;shared state&quot;, value: 0 };<br />⁠<br />⁠const increment = () =&gt; {<br />⁠  sharedState.value += 1;<br />⁠};<br />⁠<br />⁠const decrement = () =&gt; {<br />⁠  sharedState.value -= 1;<br />⁠};<br />⁠<br />⁠increment();<br />⁠decrement();<br />⁠decrement();<br />⁠increment();<br />⁠decrement();<br />⁠increment();<br />⁠<br />⁠⁠console.log(sharedState); // { type: &quot;shared state&quot;, value: 0 }</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;target=99&amp;jsx=0&amp;module=1&amp;ts=4.0.2#code/MYewdgzgLgBBAWBDATgUwCYGUqKqmAvDAN4xQCeADqgFwwBECKGcOe9ANDAG6IA2AV1owADDAC+AbgBQ00JFgBLMMDQBbVGFhEAFAEpCAPhLSYcJGixtUAOl6D8AaiIBGGVNnzoMdKlWoNLUIYfSMTMyZLbFxbeyEYAFpXdxlpZX9AqH0ZXwzNLL0cv3V87LSVEq0y3MqCmXTasrlwCBA+Wz4QAHMdSIxovEKYAHphkjIqYXowcAS+9FYYzh5+IToxcVkgA" target="_blank">Playground</a>&nbsp;</figcaption><p>This example is not exactly concurrent, but it illustrates the challenge of tracking the value of our shared state throughout the application&#39;s flow. If we also had different modules consuming and modifying <mark>sharedState</mark> we might run into issues when trying to determine the state of our application at any given moment during its execution.</p><p>But all these issues can be easily solved by removing the shared state and generating a new state with each operation performed:</p><pre><code>language-javascript<br /><br />const initialState = { type: &quot;non-shared state&quot;, value: 0 };<br />⁠<br />⁠const increment = (state) =&gt; ({<br />⁠  ...state,<br />⁠  value: state.value + 1,<br />⁠});<br />⁠<br />⁠const decrement = (state) =&gt; ({<br />⁠  ...state,<br />⁠  value: state.value - 1,<br />⁠});<br />⁠<br />⁠const stateIncremented = increment(initialState);<br />⁠const initialState2 = decrement(stateIncremented);<br />⁠const initialDecremented = decrement(initialState2);<br />⁠const initialState3 = increment(initialDecremented);<br />⁠const stateDecremented2 = decrement(initialState3);<br />⁠const initialState4 = increment(stateDecremented2);<br />⁠<br />⁠console.log(initialState4); // { type: &quot;non-shared state&quot;, value: 0 }</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;target=99&amp;jsx=0&amp;module=1&amp;ts=4.0.2&amp;ssl=22&amp;ssc=1&amp;pln=1&amp;pc=1#code/MYewdgzgLgBAlmOU4EMA2BlKKoFMYC8MA3jFAJ4AOuAXDAERjgC0EAFigE64AmM0OXPQA0MAG7oArrRgAGGAF8A3ACgVoSLATBuAW1xhYRABQC8ASkIA+GMeIqYMAHQuzuYQ-FSZbpxLTSMADUMACMHgrmqurg0DA8uDq4+oaEtm6WBDZ2ni5Obh6O-tJ0vsX4zGERUWoacW4AkmBJKXh8RNp6BlDGCEiomNgWqnVaiMjoWIIATGkJLd2mQ7hNC4a8NaPw4wMAIold6+3xB8mLfRODM5uxY-2TywDMaZ1nhr076PtrbTea-Mtvoc2rMiPNgR97lc8I8-nELgMpngACwvZoQtxAt4gmoxSAgNC4JxoEAAc0hlyRuGRURgAHo6SQyFQZIwWOwuLwAYIRF4AjJ5Ao1EA" target="_blank">Playground</a>&nbsp;</figcaption><p>The variable names chosen aren&#39;t particularly elegant or expressive, but they were selected to highlight the advantage of this code over the previous one. We have moved the program&#39;s state from a mutable variable, whose content is only known at runtime, to an immutable variable, whose content is predictable at compile time. This makes the new version of our program easier to understand, debug, and test. In this sense immutability improves the predictability of our application.</p><p>We could even keep a history of all the states of our application, which would make it easier for us to debug and perform post-mortem analysis if any issues arise.</p><h1>Purity </h1><p>Functional programming aims for simplicity and predictability in our programs, which is why it relies heavily on functions. And for functions to be predictable they must return the same output for the same input. In this sense, a function represents an immutable relationship between two sets: input and output, and this relationship must remain constant.</p><pre><code>language-javascript<br /><br />⁠const pureFunction = (a, b) =&gt; a &lt; b;<br />⁠console.log(pureFunction(1, 2)); // true<br />⁠<br />⁠const impureFunction = (a, b) =&gt; (Math.random() &gt; 0.5 ? a &lt; b : a &gt; b);<br />⁠console.log(impureFunction(1, 2)); // true or false</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;target=99&amp;jsx=0&amp;module=1&amp;ts=4.0.2#code/MYewdgzgLgBADgVwE4FMBiCzCgS3DAXhgAoBDAGhgCMBKQgPhlJgB5qBuAKFEhABsUAOj4gA5sUSoMWXOGIBGSgCYaNdjAD0GmFCQIUnbuGgwcAW0npM2PGEIkK1OgUbEAsqSgALQUlJgAExAzYjpGAAZBAFYYAH4mVmoYAC4ExlouHgh+IRFxc0tpGzlFGBU1TW1dfRgQJBgAM1I+CAMgA" target="_blank">Playground</a>&nbsp;</figcaption><p>Purity makes predictability easier, but it also allows us to memoize function results, avoiding unnecessary computations.</p><h1>Arity</h1><ul><p>Arity refers to the number of parameters a function takes.</p></ul><ul><li>A function with an arity of 0 doesn’t take any parameters: it’s called nullary.</li><li>A function with an arity of 1 takes just one parameter: it’s unary.</li><li>A function with an arity of 2 takes two parameters: it’s binary.</li><li>A function with an arity of n can take any number of parameters: it’s called n-ary, also known as variadic.</li></ul><pre><code>language-javascript<br /><br />⁠const nullaryFunction = () =&gt; &quot;Hello world&quot;;<br />⁠console.log(nullaryFunction()); // hello world<br />⁠<br />⁠const unaryFunction = (greeting) =&gt; `${greeting} world`;<br />⁠console.log(unaryFunction(&quot;hello&quot;)); // hello world<br />⁠<br />⁠const binaryFunction = (greeting, subject) =&gt; `${greeting} ${subject}`;<br />⁠console.log(binaryFunction(&quot;hello&quot;, &quot;world&quot;)); // hello world<br />⁠<br />⁠const nAryFunction = (...strings) =&gt; <br />⁠  strings.reduce((acc, curr) =&gt; `${acc}${curr} `, &quot;&quot;);<br />⁠console.log(nAryFunction(&quot;hello&quot;, &quot;world&quot;, &quot;and&quot;, &quot;pluton&quot;)); <br />⁠// hello world and pluton</code></pre><figcaption>Arities, run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;target=99&amp;jsx=0&amp;module=1&amp;ts=4.0.2#code/MYewdgzgLgBGCuAbRBDATgTwGLzMKAluDALwwAUAlKQHwwBEAEgKbIgwDuIaiAJvQG4AUKEghEzAHSIQAc3IJk6bLnxEwVSgJgB6HTAAWrGZ258hI8NBi5lOPIWJlystM2aEws6iToADABIAb1d3T1kAX1MeXj9hUQhxKRl5W0x7NXByeiM2ekotXX1cky4YiwTYACMCMDtVRzBSClCPWtkAGhgIeCqAK2Z8H39g1vCo4J7+wagIuMsxCWk5chq69Ib1bJKQei76Mr58wr1DY3ZD3gqrWDAAQQ2HdWbySTfoNHaIYZghGG6oJ8vBBJG5ePBgMxyOQUMBgF1gPA0GgfoEgrDgBFgojkVE-Pt8vErEllvJ7o9Mhocuc9gxLrT6CgwPx9gAHRDwKDgY7aISnHbRPgwJm8GDszngIA" target="_blank">Playground</a>&nbsp;</figcaption><p>Nothing special here, just some terminology. But it&#39;s important, as unary functions are at the core of some operations in functional programming.</p><h1>Currying</h1><p>Currying is the process of transforming a function that takes multiple parameters —with an arity greater than 1— into a series of nested unary functions, that is, functions that take only one parameter.</p><pre><code>language-javascript<br /><br />⁠// Non curried function<br />⁠const sum = (a, b, c) =&gt; a + b + c;<br />⁠const result = sum(1, 2, 3);<br />⁠console.log(result); // 6<br />⁠<br />⁠// Curried function<br />⁠const sum = (a) =&gt; (b) =&gt; (c) =&gt; a + b + c;<br />⁠⁠const result = sum(1)(2)(3);<br />⁠console.log(result); // 6</code></pre><figcaption>Currying, run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;target=99&amp;jsx=0&amp;module=1&amp;ts=4.0.2#code/PTAEDkHsDtQYwK4CckEsCmATUAzB04AXVGAKDhgGdDRKEBbUAXlAAoBDAGlACNu4AlMwB8odqADUvSfADc5KjSTo6AGxos69VgEZuAJm4BmAfIrRKkVegB0qyAHNWytYVOgQoAGylSngMLIaFi4+EQk0AoWNIgoGJgAygzMbOxCTKKsPOmZgiJiMjwycGaKoC4I6vopscGJDLoCrPpNJqUWVrb2ThVV7p5eQA" target="_blank">Playground</a>&nbsp;</figcaption><p>As we&#39;ll see later, this is a key technique in functional programming: there are many operations where we need functions to have a similar structure —one input for one output— allowing them to be combined in different ways.</p><h1>Partial application</h1><p>Partial application refers to the process of transforming a function that takes various parameters into another function that only takes some of those parameters. It &quot;fixes&quot; certain arguments within its context and returns a new function that will take the remaining arguments, combining them with the prefixed ones.</p><p>This is really useful as it allows us to create functions with parameters that are pre-applied, which means we can specialize functions.</p><p>For example, let&#39;s say we have a function called <mark>createUrl</mark> that takes three string parameters: <mark>protocol</mark>, <mark>domain</mark>, and <mark>path</mark>, combining them and returning another string:</p><pre><code>language-javascript<br /><br />⁠const createUrl = (scheme, domain, path) =&gt; `${scheme}://${domain}/${path}`;<br />⁠<br />⁠const httpUrl = createUrl(&quot;http&quot;, &quot;example.com&quot;, &quot;hello&quot;);<br />⁠console.log(httpUrl); // &quot;http://example.com/hello&quot;<br />⁠<br />⁠const httpsUrl = createUrl(&quot;https&quot;, &quot;example.com&quot;, &quot;hello&quot;);<br />⁠console.log(httpsUrl); // &quot;https://example.com/hello&quot;</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;target=99&amp;jsx=0&amp;module=1&amp;ts=4.0.2#code/MYewdgzgLgBMBOBTAhlRBVeAbGBeGAFBMABaIC2iANDACYjnICWYNADqiQJR4B8MAAwAkAb2JlKAXwBcAelmj6jFpIUiOUEpIEBuAFB7QkWCShQ2mHPgQo0lggCJT5hzQeIAHsnJssiAHSg5K4wTohYWCAOXPpGECB+-pEA5gTOFtgxMPKh6XKynt6+AUGyZBFRBnEmZmwQlnhwSKgY2I7pECHuXj6JQV3lkdGx4PGJKWm19Zk62bK5U-mFvSUMZeFDQA" target="_blank">Playground</a>&nbsp;</figcaption><p>We may probably use this function in multiple places in our code with &quot;http&quot; or &quot;https&quot;. To write more declarative code and avoid passing the <mark>scheme</mark> parameter every time we need a URL we can create two specialized versions of <mark>createUrl</mark>: <mark>createHttpUrl</mark> and <mark>createHttpsUrl</mark>, applying the <mark>scheme</mark> parameter in the context of these functions.</p><pre><code>language-javascript<br /><br />⁠const createUrl = (scheme, domain, path) =&gt; `${scheme}://${domain}/${path}`;<br />⁠<br />⁠// Partial application: fixing `scheme` parameter<br />⁠const createUrlWithProtocol = (scheme) =&gt; <br />⁠  (domain, path) =&gt; createUrl(scheme, domain, path);<br />⁠⁠<br />⁠⁠const createHttpUrl = createUrlWithProtocol(&quot;http&quot;);<br />⁠const createHttpsUrl = createUrlWithProtocol(&quot;https&quot;);<br />⁠<br />⁠const httpUrl = createHttpUrl(&quot;http&quot;, &quot;example.com&quot;, &quot;hello&quot;);<br />⁠console.log(httpUrl); // &quot;http://example.com/hello&quot;<br />⁠<br />⁠⁠const httpsUrl = createHttpsUrl(&quot;https&quot;, &quot;example.com&quot;, &quot;hello&quot;);<br />⁠console.log(httpsUrl); // &quot;https://example.com/hello&quot;</code></pre><figcaption>With partial application, run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;target=99&amp;jsx=0&amp;module=1&amp;ts=4.0.2#code/MYewdgzgLgBMBOBTAhlRBVeAbGBeGAFBMABaIC2iANDACYjnICWYNADqiQJR4B8MAAwAkAb2JlKAXwBcAelmj6jFpIUiOUEpIEBuAFB75MAArJ4UJshzI2bLE2Com4aTABmTAB4sA5oPEUiAIwHPDIlGjweqCQsAgoaJhYAOpMmsbwIFAgoDj4RKSBPLj8BErMrCGcxbx6MHBIqBjYBRLUdAwV7NX60eDQDQmIABJQUGxJeINNSanpmdm5BABEJGNsy1z6MQPxTaPjEJP4e4nYcyQZWTkgWCtrh5u9O7APE9hTpyPrSSuInuE7IgAHSgcjLGirRBYLAgJ59SC3EGwnwEN5JLYwIyrdZyWT-QFYEFg2RkGFwgwvGBvI4fE6NNAHNi0u7LAnkIGghgQmBQ8nwnZI4EotHrFmY7E0vHszkksmw5Z6IA" target="_blank">Playground</a>&nbsp;</figcaption><p>These new functions are semantically more expressive, and they reduce the arity of the functions we use to create the URLs.</p><h1>Point-free style</h1><p>Point-free style is a way of writing functions where they are processed without referencing their parameters —points—. </p><p>Let&#39;s take a look at an example: when we pass a function as an argument to another function, it’s common practice to write it directly inside that function:</p><pre><code>language-javascript<br /><br />⁠const userName = users.map(<br />⁠  ({ first, lastName }) =&gt; `${first} ${lastName}`<br />⁠);</code></pre><figcaption>With parameters</figcaption><p>In a point-free style we would extract the function declaration and store it in a variable, which is then passed to the new function.</p><pre><code>language-javascript<br /><br />⁠const composeName = ({ first, lastName }) =&gt; `${first} ${lastName}`;<br />⁠const userName = users.map(composeName⁠);</code></pre><figcaption>Point-free style</figcaption><p>In general point-free style is more declarative and readable, and also makes function composition easier, as we’ll see later.</p><h1>Compose and pipe</h1><p>In algebra, function composition refers to the process of transforming a sequential set of unary functions into nested ones, so that the result of one function is passed as a parameter to the next, wrapping it.</p><p>Let&#39;s say we have two functions</p><p><span><span class="math-inline">f(x) = 2x\\
⁠⁠g(x) = x^2</span></span><br />⁠<br />We express that we compose them with the following syntax:</p><p><span><span class="math-inline">f \circ g =(g(x))</span></span></p><p>Which means that we are executing <span><span class="math-inline">g(x)</span></span> first, and then <span><span class="math-inline">f(x)</span></span> with its result. </p><p>It’s important to emphasize that composition is not commutative:</p><p><span><span class="math-inline">f \circ g \neq g \circ f</span></span></p><p>although it is associative.:</p><p><span><span class="math-inline">f(g(h(x))) = (f \circ g)(h(x)) = f(g(h(x)))</span></span>.</p><p>This can easily be translated into JavaScript, as functions are first-class citizens in this language: we can treat them like variables, so any function can accept another as a parameter.</p><p>Given two functions, we can execute one inside the other:</p><pre><code>language-javascript<br /><br />⁠⁠const f = (x) =&gt; x * 2;<br />⁠const g = (x) =&gt; x * x;<br />⁠<br />⁠const result = f(g(3));<br />⁠console.log(result); // 18</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;target=99&amp;jsx=0&amp;module=1&amp;ts=4.0.2#code/MYewdgzgLgBAZjAvDAFADwJRIHwzTAKhgCYBuAKFElgHMlVMc9C8LLxoYAnAUwgFcANrGRwUNFAGYMGClQghBPAHSCQE3gOGyYAel0wAjAA4gA" target="_blank">Playground</a>&nbsp;</figcaption><p>And let&#39;s say that this type of operation is something we do often: it would be interesting if we had a utility that, given two functions, would return them composed:</p><pre><code>⁠language-javascript<br /><br />⁠const f = (x) =&gt; x * 2;<br />⁠const g = (x) =&gt; x * x;<br />⁠<br />⁠const compose = (f, g) =&gt; (x) =&gt; f(g(x));<br />⁠<br />⁠const composed = compose(f, g);<br />⁠const resultComposed = composed(3); // 18</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;target=99&amp;jsx=0&amp;module=1&amp;ts=4.0.2#code/MYewdgzgLgBAZjAvDAFADwJRIHwzTAKhgCYBuAKFElgHMlVMc9C8LLxoZQBbABxAgBTeijgAaGDSyJc6abjgoacjGyqce-IQBN6mgYNESpFdbABOgiAFcANlADCIPgd3J9OlAGZVMAPR+MACMABxAA" target="_blank">Playground</a>&nbsp;</figcaption><p>In this case, we have a function that takes two parameters —arity 2—, performs partial application to fix them in the closure context, and returns a new function. This new function, when given a new parameter, will use the fixed ones to execute our nested functions, using the new parameter as the initial argument.</p><p>This way, the returned function is stored in the variable <mark>composed</mark>, which has <mark>f</mark> and <mark>g</mark> in its context, and will use them when called with a new argument (3).</p><p>Now let&#39;s say we want to compose three functions:</p><p><span><span class="math-inline">f \circ g \circ h = f(g(x))</span></span></p><p>Using the same logic, we can translate this into JavaScript with a function <mark>compose</mark> of arity 3:</p><pre><code>language-javascript<br /><br />⁠const f = (x) =&gt; x * 2;<br />⁠⁠const g = (x) =&gt; x * x;<br />⁠const h = (x) =&gt; x - 1;<br />⁠<br />⁠const compose = (f, g, h) =&gt; (x) =&gt; f(g(h(x)));<br />⁠<br />⁠const composed = compose(f, g, h);<br />⁠console.log(composed(3)); // 8</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;target=99&amp;jsx=0&amp;module=1&amp;ts=4.0.2#code/MYewdgzgLgBAZjAvDAFADwJRIHwzTAKhgCYBuAKFElgHMlVMc9C8KroYALe9LRXfAFoYARgqVwHUAFsADiAgBTHnAA0MGus59cvJnBQ0UnXhgzj2sGfKUATetYWKUajVvMTIIADaKAdN4gRo52KADMZqQwAPTRMAAcQA" target="_blank">Playground</a>&nbsp;</figcaption><p>It works perfectly, but it&#39;s not very scalable. The next step would be to create an n-ary function that, given any number of functions passed as parameters, returns them composed.</p><pre><code>language-javascript<br /><br />⁠const f = (x) =&gt; x * 2;<br />⁠⁠const g = (x) =&gt; x * x;<br />⁠const h = (x) =&gt; x - 1;<br />⁠<br />const compose = (...fns) =&gt; (x) =&gt;<br />⁠  fns.reduceRight((acc, curr) =&gt; curr(acc), x);<br />⁠<br />⁠const composed = compose(f, g, h);<br />⁠console.log(composed(3)); // 8</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;target=99&amp;jsx=0&amp;module=1&amp;ts=4.0.2#code/MYewdgzgLgBAZjAvDAFADwJRIHwzTAKhgCYBuAKFElgHMlVMc9C8KroYALe9LRXfAFoYARgqVwHUAFsADiAgBTHgDo1cSH1y8c5GPEgqATooAmAV2CKASgEsanKChQBDYMAA0MYOaNGt3r5Gru4YXpji7LAy8kqm9DEKiihwXjRenBhskiAANooquSA0KIlxKADMGFkwAPS1MAAcQA" target="_blank">Playground</a>&nbsp;</figcaption><p>This function takes any number of functions as individual parameters. It distributes them into an array using the spread operator <mark>...</mark>, and sets them within the closure context, returning a new function. This new function will be unary, receiving the initial data as a parameter to process our functions. It will then loop through the array of functions from right-to-left, executing them, which means it will execute the last function first with the initial data provided in the parameter.</p><p>What we&#39;ve just done is create a compose function: a very handy n-ary utility for composing any number of functions as long as they are unary.</p><p>Now, let&#39;s say we want to compose our functions, but starting from the first one to the last: instead of using <mark>Array.reduceRight</mark>, we can use <mark>Array.reduce</mark>.</p><pre><code>language-javascript<br /><br />⁠const f = (x) =&gt; x * 2;<br />⁠⁠const g = (x) =&gt; x * x;<br />⁠const h = (x) =&gt; x - 1;<br />⁠<br />const pipe = (...fns) =&gt; (x) =&gt;<br />  fns.reduce((acc, curr) =&gt; curr(acc), x);<br />⁠<br />⁠const piped = pipe(f, g, h);<br />⁠console.log(piped(3)); // 35</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;target=99&amp;jsx=0&amp;module=1&amp;ts=4.0.2#code/MYewdgzgLgBAZjAvDAFADwJRIHwzTAKhgCYBuAKFElgHMlVMc9C8KroYALe9LRXfAFoYARgqVwHAA4BLKQFMeAOhVxIfXLxzkY8SEoBO8gCYBXYPJQoAhsGAAaGMFMGDGpy4M27GR5nHssLIKxvTBlnCONI6cGGySIAA28kqJIDQo4cYoAMwYcTAA9IUwOQCsQA" target="_blank">Playground</a>&nbsp;</figcaption><p>This type of utility is known as a <mark>pipe</mark>. As we mentioned earlier, composition is not commutative, so it returns a different result compared to the <mark>compose</mark> function.</p><h1>Eager and lazy evaluation</h1><p>By &quot;eager evaluation,&quot; we refer to the computation model where a variable is evaluated immediately after the expression appears in the code. </p><p>For example, in JavaScript:</p><pre><code>language-javascript<br /><br />⁠⁠const sum = (a, b) =&gt; a + b;<br />const result = sum(1, 2); // Computed here<br />⁠console.log(result); // 3</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;target=99&amp;jsx=0&amp;module=1&amp;ts=4.0.2#code/MYewdgzgLgBBCuBbGBeGAKAhgGhgIwEpUA+GTGAanwG4AoUSWAJwFMEAbWNBRdARlwAmAtRgB6MTADCIRAAd4UFgBMYACxat64CCHYsAdOxABzdKw5QR4yQGYgA" target="_blank">Playground</a>&nbsp;</figcaption><p>As we can see, the expression is evaluated when we call the function, not when the result of the function is consumed.</p><p>With lazy evaluation, on the other hand, computation is delayed until the result is actually used.</p><p>Except for the logical operators <mark>&amp;&amp;</mark>, <mark>||</mark> and ternary operator, JavaScript does not support lazy evaluation. This is a problem, since our code will always consume resources for the total number of operations reflected in the code.</p><p>However, lazy evaluation can be implemented in various ways. For example, using the mentioned logical operators —though in a very limited way— or by using generators:</p><pre><code>language-javascript<br /><br />⁠function* lazySum(a, b) {<br />⁠  yield a + b;<br />⁠}<br />⁠<br />⁠let result = lazySum(1, 3); // computation delayed<br />⁠console.log(result); // not evaluated yet<br />⁠console.log(result.next().value); // 4</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;target=99&amp;jsx=0&amp;module=1&amp;ts=4.0.2#code/GYVwdgxgLglg9mAVAAgDYEMBeBPAyiAWwAp0AaZAIwEpkBvAKGWWxgFNUATZdZAakoDc9AL716qVlGQAnVgGcQqKQF40WPISIBGcgGYqA5AHojyCHAIAHEFHSwEyDu3TZWHeubBy4EgHSo4AHMiWQUlA2NTMDgpVgA3dFQQOzdmSQ8Ebz8A4NDFKF8wVgAPKCIqXwSk1giTZAAWIA" target="_blank">Playground</a>&nbsp;</figcaption><p>Here, the sum won&#39;t be executed when we call <mark>lazySum</mark>, but when we use the result and call <mark>next()</mark>. Later on, we&#39;ll explore operations in functional programming that are executed lazily.</p><h1>Conclusion</h1><p>That&#39;s all for today. All of these concepts and operations are quite common, but they are the foundation for the operations we&#39;ll cover soon. The code can be run in the TypeScript Playground, and is available at <a href="https://www.git.antoniodiaz.me/antoniodcorrea/blog-functional-programming-suporting-code/-/tree/master/src/I-basic-concepts?ref_type=heads" target="_blank">this repository</a>.</p><p>If you have any question or if you found a mistake please ping me to the address at the footer.</p></p>]]></description></item><item><title>Functional JavaScript: transformers</title><pubDate>Wed, 21 Jan 1970 00:00:00 GMT</pubDate><guid isPermaLink="true">https://www.antoniodiaz.me/en/blog/13</guid><description><![CDATA[<p><p>In our previous article we covered some of the basics of functional programming. We discussed concepts such as immutability, purity, and arity, as well as operations like partial application, currying, and composition, all of them fundamental components of this paradigm.</p><p>In this article we will build on these basic operations to create some functions that will help us to process large datasets. But first, let’s briefly review composition.</p><h1>Function composition</h1><p>When we described function composition, we started with a common definition provided in algebra:</p><blockquote>... process of transforming a sequential set of unary functions into nested ones, so that the result of one function is passed as a parameter to the next, wrapping it.</blockquote><p>We achieved this by using a function called <mark>compose</mark>, which executes right-to-left:</p><pre><code>language-javascript<br />⁠<br />⁠⁠const f = (x) =&gt; x * 2;<br />⁠const g = (x) =&gt; x * x;<br />⁠const h = (x) =&gt; x + 2;<br />⁠<br />const compose = (...fns) =&gt; (x) =&gt;<br />⁠  fns.reduceRight((acc, curr) =&gt; curr(acc), x);<br />⁠<br />⁠const composed = compose(f, g, h);<br />⁠const result = composed(3);<br />⁠console.log(result); // 50</code></pre><figcaption>Compose, run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false#code/FAYw9gdgzgLgBAMzgXjgCgB4EoUD44ZwBUcATANyiSxwDmK62eBxBl408AFg5jsvkIBqMpSqc44ALYAHMFACmvAHSqE0fvj55gcRNGUAnBQBMAriAUAlAJa0uMNGgCGIEABpJZw4c1efLm5YnthiHDTScoomDJHyCmgInrSeXFjs1PDGUGYANvCocdFoAMzp4lBguQrKuWC0aNl5MOlwAPRtcACsAAxAA" target="_blank">Playground</a>.</figcaption><p>Or a <mark>pipe</mark>, executed left-to-right:</p><pre><code>language-javascript<br />⁠<br />⁠⁠const f = (x) =&gt; x * 2;<br />⁠const g = (x) =&gt; x * x;<br />⁠const h = (x) =&gt; x + 2;<br />⁠<br />const pipe = (...fns) =&gt; (x) =&gt;<br />⁠  fns.reduce((acc, curr) =&gt; curr(acc), x);<br />⁠<br />⁠const piped = pipe(f, g, h);<br />⁠const result = piped(3);<br />⁠console.log(result); // 38</code></pre><figcaption>Pipe, run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false#code/MYewdgzgLgBAZjAvDAFADwJRIHwzTAKhgCYBuAKFElgHMlVMc9C8KroYALe9LRXfAGoSFSuA4AHAJYSApknIxUAOlVxIfbIoabtS9RGUAnWQBMArsFkoUAQ2DAANDGDmjRzS7dG7DjM8xRdlhpOVN6UOs4ZxpnTgw2cVgTCHMAG1hkSNMUAGYE8jFIEDTZZTSQGhQU9KgEmAB6BphcgA4gA" target="_blank">Playground</a>.</figcaption><p>We also mentioned that composition is not commutative, <span><span class="math-inline">f \circ g \neq g \circ f</span></span>:</p><pre><code>⁠language-javascript<br />⁠<br />⁠const composedA = compose(f, g);<br />⁠const composedB = compose(g, f);<br />⁠<br />⁠const isCommutative = composedA(3) === composedB(3);<br />⁠<br />⁠console.log(isCommutative); // false</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;target=1&amp;jsx=0&amp;module=1#code/MYewdgzgLgBAZjAvDAFADwJRIHwzTAKhgCYBuAKFElgHMlVMc9C8LLxoYBLCAYRAC2AgK5QAhlC4A3AKb04KGigDMGLIg0wlC1RgpUIIADYyAdEZBKe-IaInSZemAHpn8MUYgzyQA" target="_blank">Playground</a>.</figcaption><p>Although it is associative, <span><span class="math-inline">f \circ (g \circ h) = (f \circ g) \circ h</span></span>:</p><pre><code>language-javascript<br />⁠<br />⁠const composedA = compose(f, compose(g, h));<br />⁠const composedB = compose(compose(f, g), h);<br />⁠<br />⁠const isAssociative = composedA(3) === composedB(3);<br />⁠<br />⁠console.log(isAssociative); // true</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;target=1&amp;jsx=0&amp;module=1#code/MYewdgzgLgBAZjAvDAFADwJRIHwzTAKhgCYBuAKFElgHMlVMc9C8KroYALe9LRXfAGoSFSuA6gAtgAcQEAKY84AGhg0+uXkzgoavDKPawpshQBMAgvRNz5KFTBsLdqzhgNjqjkDNtmAQtY+pnZOdg7qrh6eHACWEBYQECDAsQCGULEAborIYZYoAMx8iHnBfv5F0ewgADbyAHS1IHrxicmpGdnyBjAA9H0wUABOAK7y5EA" target="_blank">Playground</a>.</figcaption><p>Nothing new, this was all covered in our previous article. However it’s worth reviewing, as it is essential for what we are about to discuss next.</p><h1>Working with iterables</h1><p>So far we&#39;ve seen how we can compose functions to work with primitives or objects; but we have skipped the case of iterables, such as arrays.</p><p>To handle them effectively we&#39;ll need to rely on some utilities, which we will implement next.</p><h2>Reducers</h2><p>The first function that will help us work with iterables is known as a &quot;reducer&quot;: binary functions — with an arity of two — that combine two values into a single result. </p><p>A simple reducer has the following form: </p><pre><code>⁠language-javascript<br />⁠<br />⁠const accumulate = (a, b) =&gt; a + b;<br />⁠console.log(accumulate(1, 2)); // 3<br />⁠<br />⁠const concat = (array, val) =&gt; [...array, val];<br />⁠console.log(concat([1], 2)); // [1, 2]<br />⁠<br />⁠const power = (base, exponent) =&gt; base ** exponent;<br />⁠console.log(power(2, 4)); // 16</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;target=1&amp;jsx=0&amp;module=1#code/MYewdgzgLgBAhsYBXAtkgNnKBTGBeGACjgC4YxUAjbAJwBoZKyKVqaBKZq2-APnhgBqRgG4AUKEgh02AHToQAc2KJUGLNkIBGBgCZ27ETAD0xmAGYxE8NBiTgWfDAA8AQV7EaNOAE8yrr183XgYANzh0f04YAO8fYL4YAG1ZVLhAnzCIgF1xSQhpOQVleyxCJK1svQMjU2SdGF1sq3zYAAcQAHceAkJKOAhsLlZaBmwADw6wbDAoYbZoljZE-sGYACp1mAmpmag8m0L5JUIO7ppCXQYAFhqTMy0ANjEgA" target="_blank">Playground</a>.</figcaption><p>Although it may also merge two objects:</p><pre><code>language-javascript<br />⁠<br />⁠const merge = (a, b) =&gt; ({ ...a, ...b });<br />⁠console.log(merge({ a: 1 }, { b: 2 })); // { a: 1, b: 2 }</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;target=1&amp;jsx=0&amp;module=1#code/MYewdgzgLgBAtgUwE4HMEwLwwDwBUA0MA0gHwAUAUDDAIYBcMASgqEgCbbRICWYKhuEviowARg2asOXXv2IkKASgksQ7TlB58BMAD7zMJGGQDeMAHSWahS+dEwAvooDcFCqEggANgnNeQKGSIqAimtAwAjI6EZuIwAEyOii4wAPSpMGb0MBGEcYkOFEA" target="_blank">Playground</a>.</figcaption><p>Or it may contain slightly more elaborate logic: for example, a reducer that takes a list and a value, which is added to each element of that list:</p><pre><code>language-javascript<br />⁠<br />⁠const sumEach = (iterable, val) =&gt; {<br />⁠  const result = [];<br />⁠<br />⁠  for (const item of iterable) {<br />⁠    result.push(item + val);<br />⁠  }<br />⁠<br />⁠  return result;<br />⁠};<br />⁠<br />⁠const result = sumEach([1, 2], 3);<br />⁠console.log(result); // [4, 5]</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;target=1&amp;jsx=0&amp;module=1#code/MYewdgzgLgBBCuBbAogQ2ACxgXhgCgCgYYAbAS2gC4YBBAJztQE8AeMJAIwFM6A+AGiIwAbqhLwu1dom50CASmr1GrabN44NAbyGhIsOlwQkoShszaceG3AG0AugG4CQgGYg6+PdBhkoXRBgQV1IKKHkYHWJiQ2MoADoAB3gIDDw-AJgAahExCXlnYgBfFxiuKHg6MBhY+BNnIucCbwMjOthcBBR0NNsARn4YACZ7QYBmAubwCBASLniSEABzPFqTApgAek2YWwAWQYBWeyA" target="_blank">Playground</a>.</figcaption><p>This last function is interesting, but it has a problem: it does two intertwined things. On one hand, it &quot;reduces&quot; two values into one — two integers into a single value, an array and an integer into another array, two objects into one, etc—. On the other hand, it contains some logic that is executed on the values to be reduced —adding a value to each item in the array—.</p><p>It would be perfect if we could decouple both tasks.</p><p>We can start by extracting the summing part, which we would pass as a callback, and that in turn would be a reducer. This way we can execute it with the iterable to be transformed, initialized with an initial value <mark>initialValue</mark>. And since our <mark>sumEach</mark> function will no longer be responsible for the summing, we can give it a name that aligns with what it does: <mark>reduce</mark>.</p><pre><code>language-javascript<br />⁠<br />⁠const reduce = (reducer, iterable, initialValue) =&gt; {<br />⁠  let accumulation = initialValue;<br />⁠<br />⁠  for (const item of iterable) {<br />⁠    accumulation = reducer(accumulation, item);<br />⁠  }<br />⁠<br />⁠  return accumulation;<br />⁠};<br />⁠<br />⁠const data = [1, 2, 3];<br />⁠const increaseOne = (acc, val) =&gt; acc.concat([val + 1]);<br />⁠const result = reduce(increaseOne, data, []);<br />⁠console.log(result); // [2, 3, 4]</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;target=1&amp;jsx=0&amp;module=1#code/MYewdgzgLgBATgUwCYFdgJgXhgCka9OAGhgEsoE4BDAIwBsETSxzSq6A1dlBASiwB8MAN4AoGDAawqwYCgC2KOlSilwWMi1XsudHgG5R4mADMQcXKEixyCeTBAmyFavT4jjEmXMXLV67Hw0ShxvBSUVNTAmCnleQwkAXyMJRCgUODAYMN9I8ENEw1EraBgkFSoNAG0ARhIAJhIAZgBdQxKbMGBEKggEAHkwDGxQ2RIAN3Z+TCFvADorYBUcKsm6GABqGBqW+OLwUsQIJVhA5GCcZm6EXoGhknKoKhIq3faDkAY5uhAAczwEMc6FB4jAAPRgmBVRowJokAAsLSAA" target="_blank">Playground</a>.</figcaption><p>Here we have already taken a step forward: we have managed to separate the summing operation from the reduction operation, and store it in <mark>increaseOne</mark>. And if this <mark>reduce</mark> function sounds familiar, it&#39;s because it is practically identical to JavaScript&#39;s <mark>Array.reduce</mark> method.</p><pre><code>language-javascript<br />⁠<br />⁠const data = [1, 2, 3];<br />⁠const increaseOne = (acc, val) =&gt; acc.concat([val + 1]);<br />⁠const result = data.reduce(increaseOne, []);<br />⁠console.log(result); // [2, 3, 4]</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;target=1&amp;jsx=0&amp;module=1#code/MYewdgzgLgBAJgQygmBeGBtAjAGhgJjwGYBdAbgChRJYBLMYAJwFMEJmB5MZtGACgTBgeAG4IANgEo0APhiDgAOmrAkfDGPEwA1DCwlJlatBgsIAV3Gx0iZIpZxzwZn3pNW7LszwYDR8BAg4syK4iAA5nxmllCGMAD08ZiEMER4ACwkQA" target="_blank">Playground</a>.</figcaption><p>If we now recall our <mark>compose</mark> function, we’ll see that it is using <mark>Array.reduceRight()</mark>.</p><pre><code>language-javascript<br />⁠<br />⁠const compose = (...fns) =&gt; (initialData) =&gt; <br />⁠  fns.reduceRight((acc, curr) =&gt; curr(acc), initialData);</code></pre><p>Lets see what happens by replacing <mark>Array.reduceRight()</mark> with our <mark>reduce:</mark></p><pre><code>language-javascript<br />⁠<br />⁠const compose = (...fns) =&gt; (initialData) =&gt; <br />⁠  reduce((acc, curr) =&gt; curr(acc), fns.reverse(), initialData);<br />⁠<br />⁠const functionA = (value: number) =&gt; value + 1;<br />⁠const functionB = (value: number) =&gt; value * 2;<br />⁠const functionC = (value: number) =&gt; value + 3;<br />⁠<br />⁠const composed = compose(functionA, functionB, functionC);<br />⁠const result = composed(1);<br />⁠<br />⁠console.log(result); // 9</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;target=1&amp;jsx=0&amp;module=1&amp;ts=4.2.3#code/MYewdgzgLgBATgUwCYFdgJgXhgCka9OAGhgEsoE4BDAIwBsETSxzSq6A1dlBASiwB8MAN4AoGDAawqwYCgC2KOlSilwWMi1XsudHgG5R4mADMQcXKEiwAbtwwgTZCtXp8RxiTLmLlq9dj4aJQ43gpKKmpgJHZ6fIYSAL5GEohQKHBgMGG+keCGiYaiVtAwoPIADiAQGNg4AHSNJpD8mEI4zKzsACIqVK1CxkHoOKGyJHJwcANlGXBjwLwkzRD1iDaUNThLml10vVD9RSWwJihgwP5gAIIaOLE8AFwwYAo0lDMPGADUMACMhhOpnOlyiACE7l9nq95O9poIYF8YAAqGAAJkB4FKZwuVwAwpD7NC3h8EUjfgBmY5Y2DlKo1JAaOnVBA4HGg8DXZYgq5g7m4qJ43iY6zwBAQJSwbDMhk4P7CowlEAMep0EAAczw4slwpgAHo9TAAJxAA" target="_blank">Playground</a>.</figcaption><p>It works perfectly. This makes sense, as the input and output types are almost the same. It’s worth noting that we’ve reversed the array holding the functions to be composed with <mark>Array.reverse()</mark>, since <mark>compose</mark> must execute them right-to-left.</p><p>To implement <mark>pipe</mark>, we would proceed in the same way, but without reversing the array, as it should execute the functions left-to-right.</p><pre><code>language-javascript<br />⁠<br />⁠const pipe = (...fns) =&gt; (initialData) =&gt; <br />⁠  reduce((acc, curr) =&gt; curr(acc), fns, initialData);<br />⁠<br />⁠const functionA = (value: number) =&gt; value + 1;<br />⁠const functionB = (value: number) =&gt; value * 2;<br />⁠const functionC = (value: number) =&gt; value + 3;<br />⁠<br />⁠const piped = pipe(functionA, functionB, functionC);<br />⁠const result = piped(data);<br />⁠<br />⁠console.log(result); // 7</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;target=1&amp;jsx=0&amp;module=1&amp;ts=4.2.3#code/MYewdgzgLgBATgUwCYFdgJgXhgCka9OAGhgEsoE4BDAIwBsETSxzSq6A1dlBASiwB8MAN4AoGDAawqwYCgC2KOlSilwWMi1XsudHgG5R4mADMQcXKEiwAbtwwgTZCtXp8RxiTLmLlq9dj4aJQ43gpKKmpgJHZ6fIYSAL5GEohQKHBgMGG+keCGiYaiVtAwAA6kZRjYOAB09SaQ-JhCOMys7AAiKlTNQkHoOKGyJHJwcH0wY3DDwLwkjRBMWmx03VC9RSWwJihgwP5gAIIaOLE8AFwwYAo0lJPnGADUMACMhtumewdRAEKnjyuN3kdwmghgjxgACoYAAmD7gUq7faHADCAPsQNu93BkJeAGYtojYKB5GUQBBkBoKlUcMifuAjgtvodfsyUVFUbwEdZ4AgIEpYNhSeTKUgcK9uUYSiAGLU6CAAOZ4fmC7kwAD0GpgAHYgA" target="_blank">Playground</a>.</figcaption><p>Fantastic, we have now implemented our own <mark>Array.reduce()</mark>, which is agnostic to the reducer passed to it, and we have used it in our own <mark>compose</mark> and <mark>pipe</mark> functions.</p><h2>Transformers</h2><p>Now that we have our reduce function, we can take another step forward and explore what &quot;transformers&quot; are and what they are for.</p><p>One of the most common operations that may be performed on iterables is converting each of its elements from one type <mark>A</mark> to another type <mark>B</mark>.</p><p>To achieve this we can create a <mark>map</mark> function that will receive a transformation function, which we will call <mark>mapper</mark>, and whici will be responsible for performing the operation to transform each element of the iterable. This <mark>map</mark> will create another function that will accept a reducer, which in turn will handle the operation of accumulating the elements of the iterable into a given data structure—another array, an object, an integer, etc.—independently of the transformation performed on each element of the iterable. This second function will return another reducer, which will apply both operations —the transformation (the mapper) and the accumulation (the reducer)— to the iterable passed to it:</p><pre><code>language-javascript<br />⁠<br />const map = (mapper) =&gt; (reducer) =&gt; (acc, value) =&gt;<br />⁠  reducer(acc, mapper(value));</code></pre><p>It sounds complicated, but let’s stick with the idea that our <mark>map</mark>, when called with a <mark>mapper</mark>, creates a function with a particular trait: it receives a reducer and returns another reducer.</p><p>Let’s look at the following example: given an array of integers, we can use the <mark>map</mark> function by passing it a function that will convert the integer it receives into a string. Then we call this function again, passing the accumulator to be used —returning a new array with <mark>concat</mark>— and finally pass this last function to <mark>reduce</mark> for it to be utilized.</p><pre><code>language-javascript<br />⁠<br />⁠const map = (mapper) =&gt; (reducer) =&gt; (acc, value) =&gt;<br />⁠  reducer(acc, mapper(value));<br />⁠<br />⁠const data = [1, 2, 3];<br />const integerToString = map((x) =&gt; x.toString());<br />⁠const integerToStringWithReducer = integerToString(concat);<br />⁠const result = reduce(integerToStringWithReducer, data, []);<br />⁠<br />⁠console.log(result); // [&quot;1&quot;, &quot;2&quot;, &quot;3&quot;]</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;target=1&amp;jsx=0&amp;module=1&amp;ts=4.2.3&amp;ssl=35&amp;ssc=7&amp;pln=35&amp;pc=22#code/C4TwDgpgBAShAmBXAxtAvFA3gKClAPAIIB8AFAE4IoTkBcsVq5RANFCWwJbA0CGARgBsI9QuXK8QRYlwB23Tr0EA1JYhHsAlKIDcuAoTYAhMpSRN6cczVZQTXHhKEaxEqRyid5wRSrUajbTs9PFsTUn08M2o6BmtmQ3YZSM9HAWFRcUlpFhSvBSVVQXVMt2l9INdskz0AXz1sUEgoAFleMEgE42IoDFJeZGRRNgA3f3pA3p6jPSboAGEAe1lkXmBHaV6ofsHS7I8x4pdNKfYs92IGubiYsJ6MNo6bRJMoAB8oJZW1jZrsbGQywAzsAoNFUJZGOhtuCaA4+M45AU-EcTmgejg8MJQQNkIgALaIQRrTjLLb5HyFfwNPAAM0W5G2gNkIKgh3UUEWtNSCOEJ0xeCguIJRJJZIwsPIOzxhOJPmWo38mhCUFq-yiEGAiHIsiFgxFctJsjqemZrPx7V6+jupAtT1i-VEaOmzv0FChsSstxexFdeGlitRUxSkoDUDtnVI7IgmmVKQBwNBzNWoIw0n65z2F0DTqzm3RUAA2gA6Uu8c6BgC6DTNoPga14W0LAEY2AAmNgAZmr-1rnlkPAA5jQACqLADKwHIXkHWztpFIAA96LICfwaM6oIvi8AJ1OZ6RY6bE-2h6O99PZIOAOrcAAWXqY5IHEGH5DHk8vg9IybWcb7lBAkSqZglCpBeGe74XjOt7AA+HpsPWwC8GwhaVnGCYsoswjFoIizfoBwHKlAAD0JFFgARM2FFsBRbY0VAFGdhRlZAA" target="_blank">Playground</a>.</figcaption><p>And in the same way we created a <mark>map</mark> function that transforms values, we could create a similar function to select elements from an array.</p><p>For example, instead of our <mark>map</mark>, we can create a <mark>filter</mark> function that takes another function as an argument, which we’ll call <mark>predicate</mark>, and evaluates whether a given element of the array should remain in the array or not. And just like in <mark>map</mark>, this second function will receive an accumulator responsible for the reduce operation to be performed and return another reducer. The difference is that in the case of <mark>filter</mark>, this last reducer will apply the predicate to the value in question, and if the result is <mark>true</mark>, it will add it to the array; otherwise it will discard it.</p><pre><code>language-javascript<br />⁠<br />const filter = (predicate) =&gt; (reducer) =&gt; (acc, val) =&gt; <br />⁠  predicate(val) ? reducer(acc, val) : acc;</code></pre><p>We could use this filter function in a very similar way to how we used <mark>map</mark>.</p><pre><code>language-javascript<br />⁠<br />const filter = (predicate) =&gt; (reducer) =&gt; (acc, val) =&gt;<br />⁠  predicate(val) ? reducer(acc, val) : acc;<br />⁠<br />⁠const data = [1, 2, 3];<br />⁠const isOdd = filter((x) =&gt; x % 2 !== 0);<br />⁠const isOddWithReducer = isOdd(concat);<br />⁠const result = reduce(isOddWithReducer, data, []);<br />⁠<br />⁠console.log(result); // [1, 3]</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;target=1&amp;jsx=0&amp;module=1&amp;ts=4.2.3#code/C4TwDgpgBAShAmBXAxtAvFA3gKClAPAIIB8AFAE4IoTkBcsVq5RANFCWwJbA0CGARgBsI9QuXK8QRYlwB23Tr0EA1JYhHsAlKIDcuAoTYAhMpSRN6cczVZQTXHhKEaxEqRyid5wRSrUajbTs9PFsTUn08M2o6BmtmQ3YZSM9HAWFRcUlpFhSvBSVVQXVMt2l9INdskz0AXz1sUEgoAFleMEgE42IoDFJeZGRRNgA3f3pA3p6jPSboAGEAe1lkXmBHaV6ofsHS7I8x4pdNKfYs92IGubiYsJ6MNo6bRJMoAB8oJZW1jZrsbGQywAzsAoNFUJZGOhtuCaA4+M45AU-EcTmgejg8MJQQNkIgALaIQRrTjLLb5HyFfwNPAAM0W5G2gNkIKgh3UUEWtNSCOEJ0xeCguIJRJJZIwsPIOzxhOJPmWo38mhCUFq-yiEGAiHIsiFgxFctJsjqemZrNpnEEjl6+jupDAZk4qx49H6ojRPX4i0Wwl4sg9+goUNiVluL2IAbw0sVgkjgodCCdawgpEOJwA-GDg9G2UoTvRcSq8ADgaDmc6ttJ+uc9hcY+7a5t0VAANoAOg7vHOMYAug0zaD4GteFsWwBGNgAJjYAGY+-8B54gQB5eDwLYWq00UikAAe9FkBP4NA9UF3UAApFBJ1AAIRoDAABmVJZZoM4K7XAHVuAALUNMOSn7wKQ5ZrC+i6UECRKghKUKkB+q7wD+wD-sGbBDsAvBsC2PYvq+QI+hAbaCIsADmQbQVaypQAA9LRrZQBOUBzkAA" target="_blank">Playground</a>.</figcaption><p>Just like with reduce, we can see that <mark>filter</mark> and <mark>map</mark> have their native counterparts in <mark>Array.map</mark> and <mark>Array.filter</mark>, producing similar results. However, in this case, our functions have a special trait: they can be composed. </p><p>For example, we may create two functions that first select the odd values and then add one to each of the resulting ones using <mark>pipe</mark>. ⁠ </p><pre><code>⁠language-javascript<br />⁠<br />const data = [1, 2, 3, 4, 5];<br />⁠<br />⁠const isOdd = filter((x: number) =&gt; x % 2 !== 0);<br />⁠const incrementValue = map((x: number) =&gt; x + 1);<br />⁠<br />const incrementOddValues = pipe(incrementValue, isOdd);<br />⁠const incrementValueWithReducer = incrementOddValues(concat);<br />⁠const result = reduce(incrementValueWithReducer, data, []);<br />⁠<br />⁠console.log(result); // [2, 4, 6]</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;target=1&amp;jsx=0&amp;module=1&amp;ts=4.2.3#code/C4TwDgpgBAShAmBXAxtAvFA3gKClAPAIIB8AFAE4IoTkBcsVq5RANFCWwJbA0CGARgBsI9QuXK8QRYlwB23Tr0EA1JYhHsAlKIDcuAoTYAhMpSRN6cczVZQTXHhKEaxEqRyid5wRSrUajbTs9PFsTUn08M2o6BmtmQ3YZSM9HAWFRcUlpFhSvBSVVQXVMt2l9INdskz0AXz1sUEgoAFleMEgE42IoDFJeZGRRNgA3f3pA3p6jPSboAGEAe1lkXmBHaV6ofsHS7I8x4pdNKfYs92IGubiYsJ6MNo6bRJMoAB8oJZW1jZrsbAgAA8wItyMAoNcACoSWQAZ3idy2FEYNEsKOYRm6JzQPSstxel0a4AWiwAtiDYegsPo7qQAGayQj0aG8OEIglBFls-HdEIGYxseZkBlMqBc+E8uwyKAMozMmESpj4TGfYichXswWE0IvQVsAAiZBSIvlrMVz26uTweFlpu5SpVQqt1oZ8zt5uY8wNxAq7s1UENdQayGWsPBYE4kHoS3Ji0pvX0pAAdCmGbDsT68KR8j4lPq1rwMyloqhSDtkGxkIhxBmoFXxOXNGw03ICoJ88BC8HQ+CSxo8agkX3yA4+M5W7m-Edazg8MJwQMq6TEII1pxllsc74iuoGjbQdsQ3DwYd1FBFnTUmPhCdZ9bF4hl6ufBuMMPy4+V2vlqN-Jo+bU-xRBAwDVrIUAPk+36yEG2BHmGUCku0CY6t0pBIU8sT9KItaTDiibDmi-omEWWaLr+05TMW6LlmwGGdKQp4QJo-4pHBPYypwgiOCh-JSqQYBmJwqw8PQ2FaKc-CLIswisqR2yETcSoclRZGDBR8l4IJCDCWsECMUoJwAPxQO+5FQIcJz0IufJ4Oxx51ssIlbNI-TnHsFwUThHmbDiUAANopkmvDnBRAC63YOfABZbP5ACMbAAExsAAzGwAAsbAAKwRf88HgpwsIAPLwPAWx0lxjhloC9CyI+-A0LWgJQAApFAiVQAAhGgGAAAysflngrJQpIQLIwA7lSGHVbV9WNaczUANRQHFrH2QhXjICNY3ACV8CTbCWwRpA2bDRAo3jZNXDFaVA0cZt22Xf4ADq3AABYDjQm5nRdu2lQdpBHiJd0OZQsIruCb4oqdW3nTtk2vcAH3omw0Wdmw-lhWt8EyRASaCIsADmyLg9x-5QAA9BTAXJVAmVQAAbGFQA" target="_blank">Playground</a>.</figcaption><p>And just like before, composition is not commutative, so the order of the functions matters: if instead of using <mark>pipe</mark> — left-to-right — we use compose — right-to-left — we will see a different result.</p><pre><code>language-javascript<br />⁠<br />const data = [1, 2, 3, 4, 5];<br />⁠<br />⁠const isOdd = filter((x: number) =&gt; x % 2 !== 0);<br />⁠const incrementValue = map((x: number) =&gt; x + 1);<br />⁠<br />const incrementOddValues = compose(incrementValue, isOdd);<br />⁠const incrementValueWithReducer = incrementOddValues(concat);<br />⁠const result = reduce(incrementValueWithReducer, data, []);<br />⁠<br />⁠console.log(result); // [3, 5]</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;target=1&amp;jsx=0&amp;module=1&amp;ts=4.2.3#code/C4TwDgpgBAShAmBXAxtAvFA3gKClAPAIIB8AFAE4IoTkBcsVq5RANFCWwJbA0CGARgBsI9QuXK8QRYlwB23Tr0EA1JYhHsAlKIDcuAoTYAhMpSRN6cczVZQTXHhKEaxEqRyid5wRSrUajbTs9PFsTUn08M2o6BmtmQ3YZSM9HAWFRcUlpFhSvBSVVQXVMt2l9INdskz0AXz1sCAAPMAB7cmAoUEgoABUJWQBnADN2gFsbRJMoDFJ4XmBeUU0Z4mDsbG7oAFleMEgE4zXZ3mRkUTYAN396QNX1ragAYVbZZAXHaRmoUlPz9iy7hkUGuxRcKzQayqQIajysMTCxygu32kyOUAAPs9Xu9gJ8ahtmm0Ol1wNB+rwhvFEd8KIwaJZ6cwjEcIWt4UxEXpHi8xm1BugsPpEaRhrJCPQKUNRuQJoc7MQglKRuM0QqQgZjGwnmQxRK+gMVbK1fYoGKjJLDTK5fgWc9FZbKUabYkdRqwtq2AARMgpPWO6Wq+X2P2yC0Gp3Wmx2nW5PB4MVPAPOmxPb3ECrJqPyn11BrIV6DToFvmtAX0Xn89D6UgAOnrYsGbJr+R8Si9C14zfjUGiqFIvzObGQiHEbKgI-Eg+QmjYjdrlEuNAFpFnnm8vg7i00DQ2BaGnT7Gg5grp8QcfGccgKfjB45weGEnT+iDGiEEC04r2+rd8RXUDQJu0Pz7kWIL+FArTDKkl7CCsD7xi+b4fj434YEe5DTq+76fq8Vz+Du+i1BsUQQMAo6yFASE4ahsh5tgoGdGMewzMKUxkMxqKxL8yz3HckI1hhjLUux3Y-H8+F3qsKQYdObCcQcpCguomiET2DGFp0wycIIjisaE7GkGAZicLiGg8Vo9z8K0rTCJSYlnjEwkIqJ0l4HJ4GCGJeDGQgpkLBASlKCsAD8vZMh5oIrPQfwangGkHhOOILN80i-ICpTZB4oLLJlQL3AA2vWta8ICkkALr5ppUDzIs3wFQAjGwABMbAAMxsAALGwACslV7tVnCDAA8vA8DfNpuk0AOTT0LIr78DQ45NFAACkUDNVAACEaAYAADIRjHrsglATLIwD-oKnEzXNC1LfcK0ANRQA1hEJWBXgnRAZ3AKN8CXYM3wllWpCfadEDnZdXAjWNh2DW84OQ-4ADq3AABYnuQP4I99EO-WNAOkPuuJw4llCDO+nTofSoM4z9l2o8AGNMmwtW8GwBXlW9oG2RAtaCK0ADmdIU7pO5QAA9BLUAFR1UB9UAA" target="_blank">Playground</a>.</figcaption><h2>Conclusion</h2><p>Let’s recap: we have seen what reducers are, what transformers are, and two functions related to them: mappers and filters.</p><ul><li><strong>Reducer</strong>: a pure function that accepts two values and reduces them into a single value. They cannot be composed, as they return a single value while accepting two.</li><li><strong>Transformer</strong>: function responsible for transforming data in iterables. We use them to create other types of functions that can be easily composed.A function responsible for transforming data in iterables. We use them to create other types of functions that can be easily composed.</li><li><strong>Mapper</strong>: function that accepts another function as a parameter, which converts data from type <mark>A</mark> to type <mark>B</mark> using the provided function.</li><li><strong>Filter</strong>: function that accepts a predicate function —which returns a boolean —and creates another function that will use that predicate to determine if an element from the array should be kept in the returned value or not.</li></ul><p>It’s important to have a clear understanding of these concepts, as they form the foundation for what we will cover next: transducers.</p><p>This is all for today. As always, the code can be run in the TypeScript Playground, and it’s also available for download at <a href="https://www.git.antoniodiaz.me/antoniodcorrea/blog-functional-programming-suporting-code/-/tree/master/src/II-transformers" target="_blank">git.antoniodiaz.me</a>.</p><p>If you have any questions or have found an error, feel free to reach out to me at the address shown in the footer.</p></p>]]></description></item><item><title>Functional JavaScript: transducers</title><pubDate>Wed, 21 Jan 1970 00:00:00 GMT</pubDate><guid isPermaLink="true">https://www.antoniodiaz.me/en/blog/14</guid><description><![CDATA[<p><p>This is our third article about functional programming in JavaScript. We have already covered <a href="https://www.antoniodiaz.me/en/blog/functional-javascript-basic-concepts-12" target="_blank">its basics</a> and digged into the <a href="https://www.antoniodiaz.me/es/blog/javascript-funcional-transformers-13" target="_blank">transformers</a>.<a href="https://www.antoniodiaz.me/en/blog/funcional-javascript-composing-with-types-13" target="_blank">&nbsp;</a> Now its the time to address transducers.</p><p>To do this, we will need to rely on the composition of transformers we saw earlier.</p><h2>Transformers composition</h2><p>The <mark>map</mark> and <mark>filter</mark> functions we saw in the previous article have a difference compared to those provided by <mark>Array.map</mark> and <mark>Array.filter</mark>: they create functions that receive a reducer and return another reducer.</p><pre><code>language-javascript<br />⁠<br />⁠⁠⁠// map = (fn) =&gt; (reducer) =&gt; reducer<br />⁠<br />⁠const map = (mapper) =&gt; (reducer) =&gt; (acc, val) =&gt; <br />⁠  reducer(acc, mapper(val));<br />⁠<br />const filter = (predicate) =&gt; (reducer) =&gt; (acc, val) =&gt;<br />⁠  predicate(val) ? reducer(acc, val) : acc;</code></pre><p>Which means that our transformers are composable.</p><pre><code>language-javascript<br />⁠<br />⁠(reducer) =&gt; reducer<br />            ⁠(reducer) =&gt; reducer<br />            ⁠            ⁠(reducer) =&gt; reducer ⁠...</code></pre><p>Let&#39;s try with an example: we might need to select those elements of an array that are less than five, and then calculate their squares. We can create a filter function for the selection and a mapper function for the power calculation, and use them with our <mark>reduce</mark> function.</p><pre><code>language-javascript<br />⁠⁠<br />⁠const data = [1, 2, 3, 4, 5];<br />⁠const lessThanFive = filter((x) =&gt; x &lt; 5);<br />⁠const squares = map((x: number) =&gt; power(x, 2));<br />⁠<br />⁠const filteredAndSquared = reduce(<br />⁠  lessThanFive(squares(arrayConcat)),<br />⁠  data, []<br />⁠⁠);<br />⁠console.log(filteredAndSquared); // [1, 4, 9, 16]</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;jsx=0#code/C4TwDgpgBAsghmSAnAPAQQDRQEID4oC8UAFHAMZkBcUmUAbnADYCuE12AlIftgNwBQoSFADCAewB2ZOMGARUafEVIVqaJEjgh0uLAxZsaXAvnWbtigYPDQAShAAmzMvPRY8hWAmRuc+AD6iktKyrnhWZJIAzsBQSI7O0EQoACpYAKq4xPxQcQkuSNQqZMwAtsyMMgCWktTpWFVypdQpxvj1OVCN8nAARoyGZlqpup1VEo1VTABqTKx1-Bx13FAA3p0DseQl5ZXANRKe45MzcxBWuQBmYkgkkRIxXU1QYpdPPf0QXOu5udtlFWqkk88ScBWKAL2BwaTQ4AlyAF9+J14sBmEhDv9dkCJAIERFolsNFpxFIZJ4dKRiSA1NSdHomGoljQ6YoVgBtAB03Lg1IZjAAugSHrEwGIAO7yTzEXpwKKGCRlXryLAQAAeYokEAkwGoitKyqQzP1hpWsvlUAAVJaoOrNdrgMLHpcqow5LcCJ1fHhiGBQVUQoZSEyzWIxAM4BI2p1iKDEoUoPYwa5aHho7livz078-Y4AzIIMR9FwAPx5ZNITP0JhcajbJ2xUoIQhe1NZJuIeRFOAhkw4bOx-JdxNDhTuXAD7b81jZ3Jx8FTqAd5BFs4cOHI+6PBwyOCedkARiwACYsABmLAAFiwAFYhfwt7EBlEoikABaRgBiVToSSgLrdeRiGINU9SVeQ2igNUoBQKAbw3R8oCiABHZheQgKJPA7YDQKgE0IJWMVJUrNUT3XBt-1dd1HDQCQHAAZVQ9CHBBIdiGfV8Pwkb9f2IFC0PiKIqXMUkQnXLAd2AOAsHZAUEOicMIE5RgxAAc2IADqIcWiGKY0E4SgAB6QyoEPK8sAATiwA8ADYBX4IA" target="_blank">Playground</a>.</figcaption><p>And again, let&#39;s remember we said that although composition is associative, it is not commutative: the order in which the functions are composed matters.</p><p class="centered" style="text-align: center"><span><span class="math-inline">f \circ g \neq g \circ f</span></span></p><p>&nbsp;</p><p>We could take advantage of this and, if necessary, reverse the positions of <mark>lessThanFive</mark> and <mark>squares</mark> to first calculate the squares, and then get those that are less than five.</p><pre><code>language-javascript<br />⁠<br />⁠⁠⁠const data = [1, 2, 3, 4, 5];<br />⁠⁠const squaredAndFiltered = reduce(<br />  squares(lessThanFive(arrayConcat)),<br />⁠  data, []<br />⁠);<br />⁠console.log(squaredAndFiltered); // [1, 4]</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;jsx=0#code/C4TwDgpgBAsghmSAnAPAQQDRQEID4oC8UAFHAMZkBcUmUAbnADYCuE12AlIftgNwBQoSFADCAewB2ZOMGARUafEVIVqaJEjgh0uLAxZsaXAvnWbtigYPDQAShAAmzMvPRY8hWAmRuc+AD6iktKyrnhWZJIAzsBQSI7O0EQoACpYAKq4xPxQcQkuSNQqZMwAtsyMMgCWktTpWFVypdQpxvj1OVCN8nAARoyGZlqpup1VEo1VTABqTKx1-Bx13FAA3p0DseQl5ZXANRKe45MzcxBWuQBmYkgkkRIxXU1QYpdPPf0QXOu5udtlFWqkk88ScBWKAL2BwaTQ4AlyAF9+J14sBmEhDv9dkCJAIERFolsNFpxFIZJ4dKRiSA1NSdHomGoljQ6YoVgBtAB03Lg1IZjAAugSHrEwGIAO7yTzEXpwKKGCRlXryLAQAAeYokEAkwGoitKyqQzP1hpWsvlUAAVJaoOrNdrgMLHpcqow5LcCJ1fHhiGBQVUQoZSEyzWIxAM4BI2p1iKDEoUoPYwa5aHho7livz078-Y4AzIIMR9FwAPx5ZNITP0JhcajbJ2xUoIQhe1NZJuIeRFOAhkw4bOx-JdxNDhTuXAD7b81jZ3Jx8FTqAd5BFs4cOHI+6PBwyOCedkARiwACYsABmLAAFiwAFYhfwt7EBlEoikABaRgBiVToSSgLrdeRiGINU9SVeQ2igNUoBQKAbw3R8oCiABHZheQgKJPA7YDQKgE0IJWMVJUrNUT3XBskNQ9CHDQCQHG-QDQRBIdiBQtD4iiYhn1fD8JG-X8qXMUkQnXLAd2AOAsHZAUEOicMIE5RgxAAc1YqjQVo+jXXdRw4SgAB6fSoEPK8BX4IA" target="_blank">Playground</a>&nbsp;<a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;jsx=0#code/C4TwDgpgBAsghmSAnAPAQQDRQEID4oC8UAFHAMZkBcUmUAbnADYCuE12AlIftgNwBQoSFADCAewB2ZOMGARUafEVIVqaJEjgh0uLAxZsaXAvnWbtigYPDQAShAAmzMvPRY8hWAmRuc+AD6iktKyrnhWZJIAzsBQSI7O0EQoACpYAKq4xPxQcQkuSNQqZMwAtsyMMgCWktTpWFVypdQpxvj1OVCN8nAARoyGZlqpup1VEo1VTABqTKx1-Bx13FAA3p0DseQl5ZXANRKe45MzcxBWuQBmYkgkkRIxXU1QYpdPPf0QXOu5udtlFWqkk88ScBWKAL2BwaTQ4AlyAF9+J14sBmEhDv9dkCJAIERFolsNFpxFIZJ4dKRiSA1NSdHomGoljQ6YoVgBtAB03Lg1IZjAAugSHrEwGIAO7yTzEXpwKKGCRlXryLAQAAeYokEAkwGoitKyqQzP1hpWsvlUAAVJaoOrNdrgMLHpcqow5LcCJ1fHhiGBQVUQoZSEyzWIxAM4BI2p1iKDEoUoPYwa5aHho7livz078-Y4AzIIMR9FwAPx5ZNITP0JhcajbJ2xUoIQhe1NZJuIeRFOAhkw4bOx-JdxNDhTuXAD7b81jZ3Jx8FTqAd5BFs4cOHI+6PBwyOCedkARiwACYsABmLAAFiwAFYhfwt7EBlEoikABaRgBiVToSSgLrdeRiGINU9SVeQ2igNUoBQKAbw3R8oCiABHZheQgKJPA7YDQKgE0IJWMVJUrNUT3XBskNQ9CHDQCQHG-QDQRBIdslyFC0PiKJiGfV8Pwkb9fypcxSRCdcME6Q8T3PK9bwFcTcnZAVFgELdwwgTlGDEABzYh2Oo2j6Ndd1HDhKAAHozKgSSoEvJSgA" target="_blank">&nbsp;</a>.</figcaption><p>Or we might need to filter those elements whose squares are less than five:</p><pre><code>language-javascript<br />⁠<br />⁠⁠const data = [1, 2, 3, 4, 5];<br />⁠const isSquareLessThanFive = filter((x) =&gt; power(x, 2) &lt; 5);<br />⁠const filtered = reduce(<br />⁠  isSquareLessThanFive(arrayConcat), <br />⁠  data, ⁠[]<br />⁠);<br />⁠console.log(filtered); // [1, 2]</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;jsx=0#code/C4TwDgpgBAsghmSAnAPAQQDRQEID4oC8UAFHAMZkBcUmUAbnADYCuE12AlIftgNwBQoSFADCAewB2ZOMGARUafEVIVqaJEjgh0uLAxZsaXAvnWbtigYPDQAShAAmzMvPRY8hWAmRuc+AD6iktKyrnhWZJIAzsBQSI7O0EQoACpYAKq4xPxQcQkuSNQqZMwAtsyMMgCWktTpWFVypdQpxvj1OVCN8nAARoyGZlqpup1VEo1VTABqTKx1-Bx13FAA3p0DseQl5ZXANRKe45MzcxBWuQBmYkgkkRIxXU1QYpdPPf0QXOu5udtlFWqkk88ScBWKAL2BwaTQ4AlyAF9+J14sBmEhDv9dkCJAIERFolsNFpxFIZJ4dKRiSA1NSdHomGoljQ6YoVgBtAB03Lg1IZjAAugSHrEwGIAO7yTzEXpwKKGCRlXryLAQAAeYokEAkwGoitKyqQzP1hpWsvlUAAVJaoOrNdrgMLHpcqow5LcCJ1fHhiGBQVUQoZSEyzWIxAM4BI2p1iKDEoUoPYwa5aHho7livz078-Y4AzIIMR9FwAPx5ZNITP0JhcajbJ2xBwyOCedkARgwACYMABmDAAFgwAFYhfx7o8BlEoikABaRgBiVToSSgLrd8mIxDVeqV8jaUDVUBQUCHcLHhK6UQAygBHZi8iAAGQgU9nC6XK7X7s326gJr3KxipKlZqlgnZcMep4Nqurruo4IL5IWVTXneD7Pq+c4SIuy5UuYpIhBwWBNsAcBYOyApnuO4YQJyjBiAA5sQX7yI4cJQAA9OxUDtmBAr8EAA" target="_blank">Playground</a>.</figcaption><p>Or we could even square each element and reduce it to a single value.</p><pre><code>language-javascript<br />⁠<br />⁠const accumulate = (a: number, b: number): number =&gt; a + b;<br />⁠<br />⁠⁠⁠const data = [1, 2, 3, 4, 5];<br />const filteredSquaredAndAccumulated = reduce(<br />⁠  lessThanFive(squares(accumulate)),<br />⁠  data,<br />⁠  0<br />⁠);<br />⁠console.log(filteredSquaredAndAccumulated); // 30</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;jsx=0#code/C4TwDgpgBAsghmSAnAPAQQDRQEID4oC8UAFHAMZkBcUmUAbnADYCuE12AlIftgNwBQoSFADCAewB2ZOMGARUafEVIVqaJEjgh0uLAxZsaXAvnWbtigYPDQAShAAmzMvPRY8hWAmRuc+AD6iktKyrnhWZJIAzsBQSI7O0EQoACpYAKq4xPxQcQkuSNQqZMwAtsyMMgCWktTpWFVypdQpxvj1OVCN8nAARoyGZlqpup1VEo1VTABqTKx1-Bx13FAA3p0DseQl5ZXANRKe45MzcxBWuQBmYkgkkRIxXU1QYpdPPf0QXOu5udtlFWqkk88ScBWKAL2BwaTQ4AlyAF9+J14sBmEhDv9dkCJAIERFolsKJCZEkSHBqBIyr15FhepTqfIllAqaUabcTFA4FAANRQXoEh6xMBiADu8k8xF6cCihlZ7KwEAAHiKJBAJMAGWymVr2StpbKoAAqI1QZWq9XAQWPS5VRhyDmdXx4YhgUFVEKGUhqNr8sRiAZwCRtTrEUGJQpQexg1y0PAh3LFPRMBO-N2OD2k4j6LgAfjyMaQSfoKag1G21tipQQhCdcay1cQ8iKFKMK043FD4YK1GjEeduFTxf0rFTuW78mLjeQ2bOHDhyPujwcMm5RAA2gBGLAAJiwAGYsAAWLAAVgAugIl7EBlEoikABZBgBiVToZNt9snxCVuqZKyVKAUCgU8F34a8oCiABHZg4HiKJPEbYgfz-JBfRFcUiyVXd50rKBPwdRw0AkBw0GJbE5AcEF8ggbJclve8nwkV932IaDYPgiEKK+DgME6FdgDgPjcgABkWK9ogDCAADpGDEABzYgCPkIiSLInZAUouEoAAeh0qB9zEoA" target="_blank">Playground</a>.</figcaption><p>And since our transformers can be composed, we can use our <mark>compose</mark> function for all these operations:</p><pre><code>⁠⁠language-javascript<br />⁠<br />⁠const compose = (...fns) =&gt; (items) =&gt;<br />  fns.reduceRight((acc, curr) =&gt; curr(acc), items);<br />⁠<br />⁠⁠⁠const data = [1, 2, 3, 4, 5];<br />⁠const filterAndSquare = compose(lessThanFive, squares);<br />⁠<br />⁠const filteredSquaredAndAccumulated = reduce(<br />⁠  filterAndSquare(accumulate), data, 0<br />⁠);<br />⁠<br />⁠console.log(filteredSquaredAndAccumulated); // 30</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;jsx=0#code/C4TwDgpgBAsghmSAnAPAQQDRQEID4oC8UAFHAMZkBcUmUAbnADYCuE12AlIftgNwBQoSFADCAewB2ZOMGARUafEVIVqaJEjgh0uLAxZsaXAvnWbtigYPDQAShAAmzMvPRY8hWAmRuc+AD6iktKyrnhWZJIAzsBQSI7O0EQoACpYAKq4xPxQcQkuSNQqZMwAtsyMMgCWktTpWFVypdQpxvj1OVCN8nAARoyGZlqpup1VEo1VTABqTKx1-Bx13FAA3p0DseQl5ZXANRKe45MzcxBWuQBmYkgkkRIxXU1QYpdPPf0QXOu5udtlFWqkk88ScBWKAL2BwaTQ4AlyAF9+J14sBmEhDv9dkCJAIEVYhNAUpoHtckKV5AAxCS+DzKBwyOBqNo4ASEoKlMBiKJJNadWlZS4SNAtElRMkUpDUgVLKDEuCkm6S6W0cL81VYESC4WihXipVUmnYTW6KBC7C6xXkw0yy3661SmmdXKYZ2iTq4eFQWmarAAESybqFIrlYolNpE-tGvzNEgtob14cdKGNomjvyFIjtSZV7lwnVl8qtypptADeIi0S2FEhMl5pGoEjKvXkWF6jeb8llTdKLduJigcCgAGooL1Kw9YlyAO7yTzEXpwHkd3utqAQAAeXIkEAkwBXfe7nf7+EXPKgACoL+ut5Jd8AJ49LlVGHJ++q88QwKCqiFDA2jBWXoxDEAYFTaTpiFBRJCigewwVcVVcAg3Jij0JgUN+b9HF-OtiH0LgAH48gQpA0PoDCoGobYBHuR4BiiKIUgACwVSkqjoXln1feRiGIDcDy7FYN29KAAFY4WROjYlKBBCA-PxiFkxB5CKJlAIHThuEg6CCmoeCYJlbTUO2dCDEw3JdN40yoGU5B8LODhJP4aSoEiTluUMcQPPPAhIIAOkCoUokw4hulKELjIzB5-Ks2wqgAc2Y4A+JskoNBZdKyO2DgYQgCLnNchlgCHIgAG0AEYsAAJiwABmLAABYsDEgBdWiqygKIAEdmDgeIok8ZS+IEqAe0PFYZ14jcaqcjrJzNF83zQCQHAAZV6-reXcrkeWIBimNYiR2M4rAer6gbCs67i30cFb1s20EQXyCBiBu+R7o2i7XqxQE5FyqBirgLAAAYroeUCIH8xgxASt6lvkO7Vq+raHDhKAAHoMagOqQf4IA" target="_blank">Playground</a>.</figcaption><p>With this, we have all the pieces needed for the operation we are focusing on in this article: <mark>transduction</mark>.</p><h1>Transducers</h1><p>As we mentioned, our filter and map functions have their analogs in <mark>Array.filter</mark> and <mark>Array.map</mark>. One might then ask, what is the point of implementing our own functions when the <mark>Array</mark> object already has these methods.</p><p>Well, let’s consider the following scenario: suppose we have a large array —ten million elements— on which we need to perform various operations.</p><pre><code>language-javascript<br />⁠<br />⁠const data = Array.from({ length: 10000000 }, (_, index) =&gt; index + 1);</code></pre><p>To process it with <mark>Array.map</mark> and <mark>Array.filter</mark>, we need to first store the entire array in memory. And since both methods return a new array, each time we call one of them we are creating a new one.</p><p>For an array with just a few hundred elements this is not much of an issue. But it is not a scalable pattern because when we deal with a large list we could be consuming a significant amount of resources.</p><p>Additionally we could face another problem: since we&#39;re storing the processed data in memory, if the application encounters a failure and throws during the processing we may lose the data already processed.</p><p>This all happens because <mark>Array</mark> methods execute sequentially over the entire array: that is, if we want to apply <mark>Array.map</mark> and <mark>Array.filter</mark> over an array, <mark>map</mark> will first traverse the entire array, transforming all its elements and returning a new array, and then <mark>filter</mark> will do the same, selecting the elements we are interested in.</p><pre><code>language-javascript<br />⁠<br />const data = [&quot;1&quot;, &quot;2&quot;, &quot;3&quot;];<br />⁠<br />⁠const result = data<br />⁠  .map((x) =&gt; (console.log(&quot;map&quot;), Number(x)))<br />⁠  .filter((x) =&gt; (console.log(&quot;filter&quot;), x % 2 !== 0));<br />⁠console.log(result); // [1, 3]<br />⁠<br />⁠// map<br />⁠⁠// map<br />⁠⁠⁠// map<br />⁠⁠⁠// filter<br />⁠⁠⁠⁠// filter<br />⁠⁠⁠⁠// filter<br />// [1, 3]</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;ssl=6&amp;ssc=1&amp;pln=1&amp;pc=1#code/MYewdgzgLgBAtgTwIICcUEMEwLwwNoBEAjAQDQwEBMZFAzAQLoDcAUKJLGAKYDuqGWXIn6YWMGADo46AA4AKOQA8AlDgB8MOewggANlwm6QAczkFpMgsvIA5AK5wARlxRLl7sZIBmAS11QXBRV1TW09AyNTAl9-FytyRRgAUhhKGABCbFwABndWMP1DEzluPjRMZSYYAHpq-CJyWgYWIA" target="_blank">Playground</a>.</figcaption><p>It would be fantastic if we could decouple the processing of each individual element from the processing of the entire array.</p><p>To achieve this we could start with a change: instead of making successive passes over the entire array, we could try performing all the necessary actions on the first element, then the second, and so on, until we reach the last element.</p><p>Well, we do not need to implement anything to achieve this, because this is precisely what our <mark>map</mark> and <mark>filter</mark> functions are already doing with <mark>reduce</mark>.</p><pre><code>language-javascript<br />⁠<br />⁠const data = [&quot;1&quot;, &quot;2&quot;, &quot;3&quot;];<br />⁠<br />⁠const toInt = map((x: string) =&gt; (console.log(&quot;map&quot;), Number(x)));<br />⁠const isOdd = filter((x: number) =&gt; (console.log(&quot;filter&quot;), x % 2 !== 0));<br />⁠const toIntAndFilterOdds = compose(toInt, isOdd);<br />⁠const result = reduce(toIntAndFilterOdds(concat), data, []);<br />⁠<br />⁠console.log(result); <br />⁠<br />⁠⁠⁠// map<br />⁠⁠⁠// filter<br />⁠⁠⁠⁠// map<br />⁠⁠⁠// filter<br />⁠⁠// map<br />⁠⁠⁠// filter<br />⁠// [1, 3]</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;jsx=0#code/C4TwDgpgBAsghmSAnAPAQQDRQEID4oC8UAFHAMZkBcUmUAbnADYCuE12AlIftgNwBQoSFADCAewB2ZOMGARUafEVIVqaJEjgh0uLAxZsaXAvnWbtigYPDQAShAAmzMvPRY8hWAmRuc+AD6iktKyrnhWQtAAKpoSAM4AZmJIALbyAPq+HsoOMnBqxjwRNkEpYGJx0EQA3vxQUFm4xAkSaNQxcPFJqRmNHO2xiclpSJm04XUN41giTS1tUB1dw73YM7pQLdgDnUM9o307y-tj6wL1WTNYACJNk-XzR3sjmSI3uvebEtuLg90vKDWog+9QeEhET3+vXGuEm-V+uyhB1otwEAF8rGRJHFgFAkI5nFUGlEsABVO71fFOFxIagqMjMFLMRgyACWkmopKwrLkKXahSgXMmPPkcAARoxDGYtCgoiCoKyJDzWUwAGpMVic-jw0ncKC1eqS3HkBlMlnAdkSTyK5VqjUQKwPZIkLHxXEilJQMQJBVyTQSiBcA2gk2M5lsySeKmEpD0sPmy3c3kcc5QNH8Sb44DMJBW0NmiMSdGY7G410hTw6UgaLRqGsWDb6Ap18w6PUAbQAdN24PW9EwALolt1QLFlCqGcTjyqESbEbudlpxQpzj3L7ifJed6MuWysgDmAAtgMR6VgGRoBRfYyaOEmICll8OcZtWYw-bOLjDiGAqayQoYpAFHqYpiGIkqdCu9TEDu8jUPY1KuDCUEkCa-aMCh9S-o4-4yBAxD6FwAD8eIEjSZ70EwXDUCaz64ikCCflM7hNAxiBwahwEmDgKEwWRHEITGfQbtBaGUQYmGkYhN4UFgbHIAR9ocCmGaui+uTAHAnjtgARAAjDpWA6QATIZUA6QAzDpQ6qaWUDAGIACSEi4kQbGngAHtQOJIIq+4CsQangRAnaMGI+7EDpbE6XeUAAHKMmK8jEB5ykqWp7pxAA8g4DieAkb5+p51ASIl8gBUFkqheFkUFe+8gxVgHlQAApFAxlQAAhAQRAAAzKQIGX2U5LloBIDgAGKFfIOUOHEnhjuUlTEA5znANy2W5eldn4nEzKuVJhIrSNwBjZN01ILNcSBcEMixRpcBYO2A4qfwlUhWFEW7ftKZQAA9H9UDtnpWAWQOQA" target="_blank">Playground</a>.</figcaption><p>Although it seems like a small difference, it is not, as it opens the door to transform <mark>reduce</mark> into a function that, instead of receiving a transformer with a reducer already applied, receives them separately and applies them within itself.</p><p>In this way, instead of reducing with <mark>reduce</mark>:</p><pre><code>language-javascript<br />⁠<br />⁠⁠const reduce = (reducer, iterable, initialValue) =&gt; {<br />⁠  let acc = initialValue;<br />⁠<br />⁠  for (const item of iterable) {<br />⁠    acc = reducer(acc, item);<br />⁠  }<br />⁠<br />⁠  return acc;<br />⁠};</code></pre><p>We would use <mark>transduce</mark>, which would look like this:</p><pre><code>language-javascript<br /><br />⁠const transduce = (<br />⁠  transformer, <br />⁠  reducer, <br />  ⁠iterable,<br />⁠  initialValue<br />⁠) =&gt; {<br />⁠⁠  let acc = initialValue;<br />⁠  const transformedReducer = transformer(reducer);<br />⁠<br />⁠  for (const item of iterable) {<br />⁠    acc = transformedReducer(acc, item);<br />⁠  }<br />⁠<br />⁠  return acc;<br />⁠};<br />⁠<br />⁠const data = [&quot;1&quot;, &quot;2&quot;, &quot;3&quot;];<br />⁠<br />⁠const toInt = map((x: string) =&gt; (console.log(&quot;map&quot;), Number(x)));<br />⁠const isOdd = filter((x: number) =&gt; (console.log(&quot;filter&quot;), x % 2 !== 0));<br />⁠const toIntAndFilterOdds = compose(toInt, isOdd);<br />const result = transduce(toIntAndFilterOdds, concat, data, []);<br />⁠<br />⁠console.log(result);<br />⁠⁠<br />⁠⁠⁠// map<br />⁠⁠⁠// filter<br />⁠⁠⁠⁠// map<br />⁠⁠⁠// filter<br />⁠⁠// map<br />⁠⁠⁠// filter<br />⁠// [1, 3]</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;jsx=0#code/C4TwDgpgBAsghmSAnAPAQQDRQEID4oC8UAFHAMZkBcUmUAbnADYCuE12AlIftgNwBQoSFADCAewB2ZOMGARUafEVIVqaJEjgh0uLAxZsaXAvnWbtigYPDQAShAAmzMvPRY8hWAmRuc+AD6iktKyrnhWQtAAKpoSAM4AZmJIALbyAPq+HsoOMnBqxjwRNkEpYGJx0EQA3vxQUFm4xAkSaNQxcPFJqRmNHO2xiclpSJm04XUN41giTS1tUB1dw73YM7pQLdgDnUM9o307y-tj6wL1WTNYACJNk-XzR3sjmSI3uvebEtuLg90vKDWog+9QeEhET3+vXGuEm-V+uyhB1otwEAF8rGRJHFgFAkI5nFUGlEsABVO71fFOFxIagqKhQUlYACWchS7UKjIwk1Z8jgACNGIYzFoUFEQVBmRJWcymAA1Jisaik-jw0ncKC1epC3HkMieKUy+WKiBWB7JEhY+K43kpKBiBKSuSaQUQLha0F6zxUwlIekstkcc5QNH8Sb44DMJASKB69GY7G44CDalEsVkilQZOIla0kg+mnUeyp1Akxm4Tn09oBiDsxmcknhgmFqDF33p8vc+q8l1CtQaUXkruS6XAWWMBUGdqq9oaj1WnFZv4rBxtmmebPHEbEAvyIOTHWxigG0fjyesM2bC3EBc2tn2x09gVC92fL1ETfPRxr+T+p21-d6lDJtI2jI8yHjMNbygK0Qk8HRSAHEB+3MHQ9CYAoUNFRQNQAbQAOkIuAkPQxgAF0E2tGCxDKCpDHEWjKkISZiEI-CWjiQoWNtTjuE+Dj8N3WxmQAcwAC2AYg-zIKMkE5GSNHpDgaxSTjKMXBJmUYZ1mIuGFiDAKlmRCQxSAKDV+TEMQhU6Lj6h3Zt5CLRyFHcCs+PsvVSLs0FDMcYyZAgYh9C4AB+PEXL-EKoGoOMoMTKAUgQXSpjc4gksQJySHyIwNU4Dz8xc5ySz6AqopNHzKUirzEu8X99FYDh934aDcmAOBPFwgAiABGLqsC6gAmfqoC6gBmLqKPiqjgDEABJCRcSIDKpIAD2oHEkClETKwXayIHwxgxBE4guoyrrlKgAA5ZgUn5X9Vqa-doOZOIAHkHAcTxNO039iHWqAJFu+65I1G9sX2w7jtOn7nQurBVqgABSKBBqgABCAgiAABiagRoNmhbgDQCQHAAMS050PocOJPCxRigsJxaWXez7noS-E4mYbSNxTQliCZ4nSYp36kGpuIsFgmQsDauAsFwsjmr2oUoZOznueAIMoAAem1qBcJ6rAxrIoA" target="_blank">Playground</a>.</figcaption><p>This is a transducer: a function that takes a transformer —which can be a series of composed transformers— and a reducer —responsible for the reduction operation— along with an iterable and an initial value, and will reduce the iterable over the initial value using the transformer and the reducer.</p><p>Transducers have a significant efficiency advantage over method chaining, as seen with the <mark>Array</mark> methods. This becomes clear if we revisit the large array scenario we discussed earlier.</p><p>Let’s say we have a list of ten million products with different prices that we sell remotely, with a shipping cost of ten dollars. Buyers can finance the payment in twelve monthly installments, but only if each resulting monthly installment is an integer —without decimals—. With this, we have been asked to find the highest spending a customer can make when buying a financeable product.</p><p>We can do this with <mark>Array</mark> methods:</p><pre><code>language-javascript<br />⁠<br />⁠// Array with 10.000.000 elements<br />⁠const data = [<br />⁠  { name: &quot;Product 1&quot;, price: 73 },<br />⁠  ...<br />⁠];<br />⁠<br />⁠const addShippingCosts = (product: Product) =&gt; product.price + 10;<br />⁠const isEligibleForFinancing = (price: number) =&gt; price % 12 === 0;<br />⁠const getBiggerExpense = (a: number, b: number) =&gt; (a &gt; b ? a : b);<br />⁠<br />⁠console.time(&quot;array_methods&quot;);<br />⁠const result = data<br />⁠  .map(addShippingCosts)<br />⁠  .filter(isEligibleForFinancing)<br />⁠  .reduce(getBiggerExpense);<br />⁠<br />console.log(result); // 120<br />⁠<br />⁠console.timeEnd(&quot;array_methods&quot;); // 141</code></pre><figcaption>⁠Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false#code/C4TwDgpgBACgTgewCYFcDGwoF4oG8oB2AhgLYQBcUAzsHAJYEDmA3FGPWhYSiQEYRwoAX2YAoUWgQEaUJEWBFKAQThwiIADzxk6YAD5sUFWpAAKAIwAGazcsBKUVCgA6AGZ0ANh9MoCSCO4EEEgOTs4kRGCmpgD6ADRQDP4AHnbYBriOTlAA9DmwiKgYUADudMAAFlC8dIyMEDLsdJxZTnSuUKZJEMnYWDgAzKHZTnAQwChwBHitI4SkXABE2kWYZZXVtfWNHNCV8olUUIFEBGh0RLweEItxsyNNnJTmVndzwmKzYxNTM+-EZEoAAMVrooAASXDdXoAaig5iEQLec0eXAArJYoHCALLyCpuDwIBBwUy4yrONR+BAkUxpABUUDR5jsCTyRjYu2q4xKEAg0wx4KgpyQ8Os4NmIiyQjsn0k0kwRCQSAAyhU6GAwAxGABhBA0I44UzsHQYSigjBpLAGY2rZyorGisRymR0KgAUQ8tToVwgADFib6GKdzkxDEbdpQCDx+HBLdbOQBSeEAJj6OEsTqkMnqwAAQlsBG7kpBpNBDYpuHwBAleJHowI450iFADLwoAB+IVQSi8GXia6YGhEODAAAqdDIhkgcFcxIiZwgzgICBKtMz8qgJD1wCLJaodAAbhA3UeCObMDg5AosuFIqZFSq1Rqtbr9cM3J5gAIuu7PYxvdc-pwIGxBnFq75jEUECmDm+Z1IWxZ8lQEB9hIWYINcziEowphbjQu5IYex6nueMq5Pk5jJpYogDlAfJIOOk44NOs5wPOnBLiua7iM6GGLthpiLMAE7Hh4kTIUglC3HRfiMdAAC01AKCOclkWyyrUtAJBUKIQA" target="_blank">Playground</a>&nbsp;</figcaption><p>Great, we get the correct result. Let’s take note of how long it takes to execute this code: at the time of writing, the TypeScript Playground shows 141 ms, though it might vary depending on the machine it’s executed on.</p><p>Now, let’s try using a transducer:</p><pre><code>language-javascript<br />⁠<br />⁠// Array with 10.000.000 elements<br />⁠const data = [<br />⁠  { name: &quot;Product 1&quot;, price: 73 },<br />⁠  ...<br />⁠];<br />⁠<br />⁠const eligibleForFinancing = filter(isEligibleForFinancing);<br />⁠const priceWithShippingCosts = map(addShippingCosts);<br />⁠const piped = pipe(eligibleForFinancing, priceWithShippingCosts);<br />⁠<br />⁠⁠console.time(&quot;transduce&quot;);<br />⁠const result = transduce(piped, getBiggerExpense, data, 0);<br />console.log(result); // 120<br />⁠console.timeEnd(&quot;transduce&quot;); // 62</code></pre><figcaption>⁠Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;jsx=0#code/C4TwDgpgBAsghmSAnAPAQQDRQEID4oC8UAFHAMZkBcUmUAbnADYCuE12AlIftgNwBQoSFADCAewB2ZOMGARUafEVIVqaJEjgh0uLAxZsaXAvnWbtigYPDQAShAAmzMvPRY8hWAmRuc+AD6iktKyrnhWQtAAKpoSAM4AZmJIALbyAPq+HsoOMnBqxjwRNkEpYGJx0EQA3vxQUFm4xAkSaNQxcPFJqRmNHO2xiclpSJm04XUN41giTS1tUB1dw73YM7pQLdgDnUM9o307y-uZk-WYZ6KTuAL1WTNYACJNl-NHeyOZIk+6rxLbi0G3U+KDWol+9XqLRE72BvXGuEm-UBuzhB1ozwEAF8rGRJHFgFAkI5nFUGlEsABVF71YlOFxIagqKhQSlYACWchS7UKrIwk058jgACNGIYzFoUFEIVB2RJOeymAA1JisaiU-jIyncKC1epiwnkMieOUK5WqiBWKHJEh4+KEwUpKBiBKyuSaUUQLh6yFGzx00lIZkcrkcW5QLH8SbE4DMJASKBG7G4-GE4CDelkqVUmlQdOolaMkgBhnUeyZ1AU1m4XnM9ohiDc1m8inRkmlqDlwPZ6v8+qCj1itQaSXUvuy+XARWMFUGdqa9o6n12gl5oErBxdhmefPHEbEEvyMOTA2JigmyfT2esK2bG3EFcOrnO10DkVi72XP1EXcfRxb+RgzdRtj3qSM21jeMzzIZMo0fKA7RCTwdFIEcQGHcwdD0JgCgwyVFB1ABtAA6Ui4DQ7DGAAXRTe0oDAdlIGocQygqKpJmIUjiJaOJCg4gAPPjISJdsIGIICyDjJBeUkjRmQ4LAeKwQTaNXBJ2UYd1CEmRpiDAOl2RCQxSAKHVhTEMQxU6ITi1EosAIUdwa24DijUomz6n0xxDJkMT9C4AB+ESKyA-yoGoJM4NTKAUgQbS7gRYhYsQeQmXyIwdU4Fz6gPOyyzsvpspINz6AtDzgsDIDkuQYh9FYDhj2sYQAAUkDEelCRqKAJDgNJqAJJA5QAc14ejBpcagJGYFJhXkCNVMJXJgHSiVtFa9rnGAJQaDQ4gAEYAAYjuOg6OEmbiNMYYhmAkBwIHUiRHDO+piOS8T0g5W6IEEpdLgAej+qB1o6qAAHdOQACygYV2SGoaIFXfTDIgS52VdYg5Tu-jCAIIgAGZnuEkTIITH0ie63rDAAImBzawch6HYfhxHxugYAIZkWU4k2OVOjIRVPSp8dyaRiaoD2w7hchHEo2EmM41Jy56h6vqoAAA1pshCQAEmqTHvqgABqcWsTVqXPNZ6gAFYDqNrx2e4xgLKDeAHdiBwxBSYguAAKigK29oUqAAZoMbkehiBgFBiAIATG3tcTW7xaO7XLhlsDGv4eC4AcBwAGUIcYhiJCG8QCW55R9I2rXqE14BeSrjriNF6BjcOgR4PZOIAFFGFh9lPQAMWSQfeakYbPD0y3uum2bpJ1FuoAAUnFgAmHGiAOjvovh4BsCZ+Ru-4yB4jJEyZ5m+QsGFSbZ6PHVSCgfBhSgIK4HC6HGvgiA+6GgexWHkgUePVx4l08OpTSgEu6937kPEeY9+Yl2PPBFuAB1SGBci7DTLsACuMUECkFzpgxA2CKi4K-tFBikAHCeCoWJH+sCAHwJAYgoaWA0EYMLiQkuODeJWFPASciwAojsjSLQ+QwI+YQGIhIMQoNvYLREnEZgmkdwZlJHpRijgsC733nDQ+x9Y6VCwEtOAWBTrb3iJZaRTshq5WUZpMMwdAZ7VXgdKMp5Y4OBEWIogyBJFSGkbI+RyD8TWOIrY4gVMpxpF7ggSoDhqBCygF4nx0AAC0UBBFIGEaIr0o0Q5509tAFIcR+BAA" target="_blank">Playground</a>&nbsp;</figcaption><p>As we can see the same result is obtained, but with a notable efficiency gain. This, of course, will depend on the time and space complexity of the algorithms used: but it’s clear that, with the same algorithms, transducers are more efficient than method chaining.</p><p>However, once we call transduce, it will attempt to process the entire array by storing it in memory, which could potentially overload the system. In other words, the current transducer is eagerly evaluated.</p><p>What we actually want is a function that allows us to process the data with lazy evaluation, so that the data is processed only on demand. And if we recall our first article, we mentioned that lazy evaluation in JavaScript can be implemented with generators. Let’s look at an example of a generator:</p><pre><code>language-javascript<br /><br />⁠function* lazySum(a, b) {<br />⁠  yield a + b;<br />⁠}<br />⁠<br />⁠let result = lazySum(1, 3);<br />⁠console.log(result); //  {} (not evaluated yet)<br />⁠console.log(result.next().value); // 4</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;target=99&amp;jsx=0&amp;module=1&amp;ts=4.0.2#code/GYVwdgxgLglg9mAVAAgDYEMBeBPAyiAWwAp0AaZAIwEpkBvAKGWWxgFNUATZdZAakoDc9AL716qVlGQAnVgGcQqKQF40WPISIBGcgGYqA5AHojyCHAIAHEFHSwEyDu3TZWHeubBy4EgHSo4AHMiWQUlA2NTMDgpVgA3dFQQOzdmSQ8Ebz8A4NDFKF8wVgAPKCIqXwSk1giTZAAWIA" target="_blank">Playground</a>&nbsp;</figcaption><p>So, let&#39;s try to implement our <mark>transduce</mark> function in a way that lazily evaluates the data:</p><pre><code>language-javascript<br />⁠<br />function* lazyTransduce(<br />⁠  transformer,<br />⁠  reducer,<br />⁠  iterable,<br />⁠  initialValue<br />⁠) {<br />⁠  const transformedReducer = transformer(reducer);<br />⁠  let acc = initialValue;<br />⁠<br />⁠  for (const item of iterable) {<br />⁠    acc = transformedReducer(acc, item);<br />⁠<br />⁠    yield acc;<br />⁠  }<br />⁠}<br /></code></pre><p>Instead of returning, <mark>lazyTransduce</mark> will return a generator that will <mark>yield</mark> its state in <mark>acc</mark> each time its <mark>next() </mark>method is executed.</p><pre><code>language-javascript<br />⁠<br />⁠// Array with 10.000.000 elements<br />⁠const data = [<br />⁠  { name: &quot;Product 1&quot;, price: 73 },<br />⁠  ...<br />⁠];<br />⁠<br />⁠const eligibleForFinancing = filter(isEligibleForFinancing);<br />⁠const priceWithShippingCosts = map(addShippingCosts);<br />⁠const piped = pipe(eligibleForFinancing, priceWithShippingCosts);<br />⁠<br />⁠const result = lazyTransduce(piped, getBiggerExpense, data, 0);<br />⁠<br />⁠console.log(&quot;result.next().value: &quot;, result.next().value); // 0<br />⁠console.log(&quot;result.next().value: &quot;, result.next().value); // 0<br />⁠console.log(&quot;result.next().value: &quot;, result.next().value); // 0<br />⁠⁠console.log(&quot;result.next().value: &quot;, result.next().value); // 120<br />⁠⁠⁠console.log(&quot;result.next().value: &quot;, result.next().value); // 120<br />⁠⁠⁠console.log(&quot;result.next().value: &quot;, result.next().value); // 120<br />⁠...</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;jsx=0#code/C4TwDgpgBAsghmSAnAPAQQDRQEID4oC8UAFHAMZkBcUmUAbnADYCuE12AlIftgNwBQoSFADCAewB2ZOMGARUafEVIVqaJEjgh0uLAxZsaXAvnWbtigYPDQAShAAmzMvPRY8hWAmRuc+AD6iktKyrnhWQtAAKpoSAM4AZmJIALbyAPq+HsoOMnBqxjwRNkEpYGJx0EQA3vxQUFm4xAkSaNQxcPFJqRmNHO2xiclpSJm04XUN41giTS1tUB1dw73YM7pQLdgDnUM9o307y-uZk-WYZ6KTuAL1WTNYACJNl-NHeyOZIk+6rxLbi0G3U+KDWol+9XqLRE72BvXGuEm-UBuzhB1ozwEAF8rGRJHFgFAkI5nFUGlEsABVF71YlOFxIagqKhQSlYACWchS7UKrIwk058jgACNGIYzFoUFEIVB2RJOeymAA1JisaiU-jIyncKC1epiwnkMieOUK5WqiBWKHJEh4+KEwUpKBiBKyuSaUUQLh6yFGzx00lIZkcrkcW5QLH8SbE4DMJASKBG7FWBLMKTAdmSABUUEYcAAXiAlnF6RApVSaVBgECVoySAGGdR7KXUBTWbhecz2iGINzWbyKdGSY2oM3A+X2-z6oKPWK1BpJdSp7L5RnzQZ2prqABxCASIXAZJS-A+u0Eqs1noOMcMzzV1G14gN+RhyYGxMUE2rxWMFUGK2bDaxBng6XLOq6M4imK3qXH6RD3scaTXsO8jBm6vavpcIDshAjAOB+ZDhpGkb8CBUB2iEng6KQC4gPO5g6HoTAFPRkqKDqADaAB0PFwLRTGMAAuri+KEmA7KQNQ4hlBUVSTMQPFcS0cSFPJAAeqmQkSKHEGhZBxkgvL6RozIcFgylYBpIn2ps7KMO6hCTI0xBgHS7IhIYpAFDqwpiGIYqdJp9YoXWN6uAiQVofoQX1K5jjuTIEDENFUAAPzaS2UVMFw1BJlGZEpAgjl3AixCFYg8hMvkRg6pw3Dyc+oUhX09X1FlBgxRlgZoeVyDJRaHCYZEUAAApIGI9KEjUUASHAaTUASSBygA5rwUCue5hgSMwKTCvIEbWeeuTANVEraGNE3OMASg0LRxAAIwAAzPS9j0cJMSl2YwxBpg4EAJHKjjvfUXHlbp6QchIf0aTqPr1AA9PDo3jZNUAAO6cgAFlAwrssty0QOeG0uJc7KusQcrQ4QBBEAAzMDWnabG8a6pcWmzfNUAAEQXajGPANjuP44TYlLS4VaYzIspxLZs1SIqnpc8ujPrWLhj3U9yuQjiUZaTGcYJnDkIc4YAAGvNXVAAAk1SUxAalQAA1FA91YqbWuxWr1AAKyPU7XgC0pjB+UG8CB7EDhiCkxBcDm3v3WZUCIzQqubTjEDAGjEB7lAvtW4mUMu89VuXDr9RYphpGiYmDgOAAypjEniRIy3iASMvKK5l1kMA1AWz3vJd5NXHE9AztPQIZHsnEACijB4+ynoAGLJEvcqdGQK2eC5XszTte2GTqo9QAApC7ABM1NEI9k-VwTwDYHjBNIDPamQPEZJeXvu3yFgwrUNtH+h8TAkDgFAfAwo0qJigNQYUmEyK4QXsvVe695Yt08ADeyqFp5zyQWKFeSA15y03i3V8ZFR4AHUsYNybitNuwAO5QDBnAWuNDEB0IqAw+B1dxKQHwkQXhSVEHLUXvglBxCVpYEodQxu7CW70JUodQkxI4jMHsp4PMhZiylhchJRwWB76P2Fi-N+e5KhYGOnALAb1Dr+QgFxYOy1iBcxUWo4AXF9xqWADHLi+g1TcywK4+yHj7beI4L4gaa1k5+xtGAwBB8JZSwBgwiW0A7QOAVPiKu8Q7EOLEE4lxhM3EhK8T4vxhglbaVUcEzxYSIkdSiUjGJSBoHxP2gLJJnIZYCzSZIDJGYslnlyY45xQT3G1LKRaaglSxklLqeUsMScmnOhaXE-e7TJaEmSd0zGvSoaZPiNkuIwz8mjKKTU0JkyNwBKqcUiZ4SFmNIvo9I5JyCmzPufU-xMzznjMuQ8yJSznmvLFHk95vy5lXO+YEiFnzHlAvuufF5QzQUjMKdUv5pSAXXJ+RiyF2LWCLOToil5-AgA" target="_blank">Playground</a>&nbsp;</figcaption><p>Finally, this is what is properly referred to as a <mark>transducer</mark>. Here, lazy evaluation allows us to process the data on demand and perform actions on it while maintaining full control over the pace and frequency at which we do so.</p><p>For example, we might want to persist the data every certain number of elements, or send notifications to external services about the data found. And all of this can be done without causing system overload, since the spatial complexity is negligible and only the memory required for each iteration step will be used.</p><p>And just like when we used our <mark>reduce</mark> function, we can pass different reducers to our transducers to accumulate data in various ways. For example, by concatenating the data into a new array using <mark>concat</mark>:</p><pre><code>language-javascript<br />⁠<br />⁠const data = [<br />⁠  { name: &quot;Product 1&quot;, price: 74 },<br />⁠  { name: &quot;Product 2&quot;, price: 93 },<br />⁠  { name: &quot;Product 3&quot;, price: 110 },<br />⁠  { name: &quot;Product 5&quot;, price: 82 },<br />⁠];<br />⁠<br />⁠const eligibleForFinancing = filter(isEligibleForFinancing);<br />⁠const priceWithShippingCosts = map(addShippingCosts);<br />⁠const piped = pipe(eligibleForFinancing, priceWithShippingCosts);<br />⁠<br />const result = lazyTransduce(piped, concat, data, []);<br />⁠<br />⁠console.log(result.next().value); // [84]<br />⁠console.log(result.next().value); // [84]<br />⁠console.log(result.next().value); // [84, 20]<br />⁠console.log(result.next().value); // [84, 120]<br />⁠console.log(result.next().done); // true</code></pre><figcaption>Run me in <a href="https://www.typescriptlang.org/play/?strict=false&amp;noImplicitAny=false&amp;strictNullChecks=false&amp;strictFunctionTypes=false&amp;strictPropertyInitialization=false&amp;strictBindCallApply=false&amp;noImplicitThis=false&amp;noImplicitReturns=false&amp;alwaysStrict=false&amp;jsx=0#code/C4TwDgpgBAsghmSAnAPAQQDRQEID4oC8UAFHAMZkBcUmUAbnADYCuE12AlIftgNwBQoSFADCAewB2ZOMGARUafEVIVqaJEjgh0uLAxZsaXAvnWbtigYPDQAShAAmzMvPRY8hWAmRuc+AD6iktKyrnhWQtAAKpoSAM4AZmJIALbyAPq+HsoOMnBqxjwRNkEpYGJx0EQA3vxQUFm4xAkSaNQxcPFJqRmNHO2xiclpSJm04XUN41giTS1tUB1dw73YM7pQLdgDnUM9o307y-uZk-WYZ6KTuAL1WTNYACJNl-NHeyOZIk+6rxLbi0G3U+KDWol+9XqLRE72BvXGuEm-UBuzhB1ozwEAF8rGRJHFgFAkI5nFUGlEsABVF71YlOFxIagqKhQSlYACWchS7UKrIwk058jgACNGIYzFoUFEIVB2RJOeymAA1JisaiU-jIyncKC1epiwnkMieOUK5WqiBWKHJEh4+KEwUpKBiBKyuSaUUQLh6yFGzx00lIZkcrkcW5QLH8SbE4DMJASKBG7FWBLMKTAdmSABUUEYcAAXiAlnF6RApVSaVBgECVoySAGGdR7KXUBTWbhecz2iGINzWbyKdGSY2oM3A+X2-z6oKPWK1BpJdSp7L5RnzQZ2prqABxCASIXAZJS-A+u0Eqs1noOMcMzzV1G14gN+RhyYGxMUE2rxWMFUGK2bDaxBng6XLOq6M4imK3qXH6RD3scaTXsO8jBm6vavpcIDshAjAOB+ZDhpGkb8CBUB2iEng6KQC4gPO5g6HoTAFPRkqKDqADaAB0PFwLRTGMAAuri+KEmA7KQNQ4hlBUVSTMQPFcS0cSFPJAAeqmQkSKHEGhZBxkgvL6RozIcFgylYBpIn2ps7KMO6hCTI0xBgHS7IhIYpAFDqwpiGIYqdJp9YoXWN6uAiQVofoQX1K5jjuTIEDENFUAAPzaS2UVMFw1BJlGZEpAgjl3AixCFYg8hMvkRg6pw3Dyc+oUhX09X1FlBgxRlgZoeVyDJRaHCYZEUAAApIGI9KEjUUASHAaTUASSBygA5rwUCue5hgSMwKTCvIEbWeeuTAHAngcZM1QzXNhgAERjRNziEgAjDdWAbS41AAOwACwRsul2zfNUB3eNk1QAATK961LR9UAAJwAMx-RdV1AyDD1kISCNQ+9hhPU9AAMyP1AD13UOjYMAKw4zDhgABzg8jwn5aJiYOA4ADKAAWEniRIy3iAScSeC5oOPdQ92TbyrkY8AXG41AADUUCEwIZHsnEACijDsst7KegAYskBtyp0ZArSLuPUNtu0vjqCsAKQq4zBCu1ABNq6zy0QMA2C697SCa2pkDxGSXkzTte1IFgwrW5HdsmCQp34MKaWJlA1DCphZG4br+tikbSAm7NUgW0QCR2e6xAa9reeG8bpul-zr5kbjADqnJc9zvMrYLwDC0Q5WkOz3eIL3FT9y3rPiZA+FEDPSW53r9dF435v829tMd8AXc82P-N9yph2EsScTMPZnh5oWxali5EmOFgFEyFgx1wFgHGCdn+L+RAXGMGIy0nwQDPvZLi+41LAGIBwLi+hWBhigAAegQVADidNvqCVIt-MUf8AFAJAXLcBkDoGwK9GtJBKC0EYLPD-HBgDT7nwIRACBUCYEDTIcg1B30sBPXBgTKhWDf7-zocAhhYCmFENYR1dhFCuHOz4fwIAA" target="_blank">Playground</a>&nbsp;</figcaption><p>There is much to say about transducers, especially because there are numerous implementations: they are behind methods offered by various libraries, like <mark>pipe</mark> in <a href="https://rxjs.dev/" target="_blank">RxJS</a>, or are directly supported, as in the case of <a href="https://ramdajs.com/docs/#transduce" target="_blank">Ramda</a>. The same goes for them as with other utilities: it is not always the best decission to implement our own ones due to the work and risk involved in developing the most efficient implementation possible. However, it’s important to be aware of their existence and their fundamentals, as they clearly show their potential.</p><p>As usual, the code can be run in the TypeScript Playground and is available for download at <a href="https://www.git.antoniodiaz.me/antoniodcorrea/blog-functional-programming-suporting-code/-/tree/master/src/III-transducers" target="_blank">git.antoniodiaz.me</a>.</p><p>If you have any questions or have found an error, feel free to contact me at the address listed in the footer.</p></p>]]></description></item><item><title>An introduction to Rust</title><pubDate>Tue, 20 Jan 1970 00:00:00 GMT</pubDate><guid isPermaLink="true">https://www.antoniodiaz.me/en/blog/1</guid><description><![CDATA[<p><h1>Background</h1><p>Rust has been gaining popularity among developers, being the most loved language in stackoverflow <a href="https://insights.stackoverflow.com/survey/2021#overview" target="_blank">survey</a> for at least the past five years; but other indexes, such as <a href="https://www.tiobe.com/tiobe-index/" target="_blank">Tiobe</a>, rank it below the 20 most used languages. It is also difficult to find developers currently working with this language, or companies using it for active development. </p><p>What does all this mean? While Rust is recognized as a valuable tool by the developer community, its application is taking time due to its specialization and particularities. Why then invest in such a language? How does the future of Rust look? To answer these questions we will have a look at the language, its syntax, its basic features and how Rust code can be written for web applications. </p><h1>Characteristics</h1><p>Rust originated within the Mozilla team in 2010 as a side project. Since then it has evolved into a community-driven language, with the <a href="https://foundation.rust-lang.org/" target="_blank">foundation.rust-lang.org</a> as its main governance institution.</p><p>It has some characteristics that, altogether, make it different from many other languages:</p><ul><li>Is a <strong>compiled</strong> language.</li><li>Is <strong>strongly typed</strong> with both <strong>nominative</strong> and <strong>structural</strong> typing.</li><li><strong>Lacks a garbage collection system</strong>, using a «borrow checker» instead.</li><li>Provides<strong> pointers/references</strong> for stack and <strong>advanced pointers </strong>for heap memory management.</li><li>Allows both <strong>object oriented</strong> and <strong>functional</strong> programming.</li><li>It is conceived specially for <strong>concurrent code</strong> development.</li><li>Is<strong> agnostic to the asynchronous</strong> runtime.</li><li>It has a<strong> test suite integrated</strong> in the language.</li></ul><p>Let&#39;s go through them to find out what they offer:</p><p>Being a compiled language, Rust will provide a lot of information about the memory usage of our program before runtime. Making use of strongly typed structures Rust guarantees that, once the program compiles, it is memory safe. Of course we as developers can make mistakes in many other ways, especially regarding business logic; but the compiler ensures that structurally our program will be as performant and coherent as possible. It is important to mention that it uses nominative typing for structs and structural for tuples: that means that two instances of different structs will have different types to the compiler even when these structs have indentical shapes. With tuples happens the opposite: two tuples with similar shapes have the same type when they have similar shape. </p><p>This happens mainly because of the lack of any garbage collection system. Languages such as Java, Python, or Javascript rely on a garbage collector to handle the memory usage and clean up unused variables. In other languages, as in C or C++, it is required to manually handle memory resources; but in Rust we have a «borrow checker» system at compilation time that ensures that, when a variable goes out of the scope of its usage, it is cleaned.</p><p>This is done automatically for values with known sizes, which are stored in the stack. For these values we can make use of C-like pointers <mark>(*&amp;)</mark> to reference and dereference them, although within some constraints imposed by Rust to avoid unsafe memory handling.</p><p>For those values whose size is not known beforehand by the compiler and have to be stored in the heap, such an array —«Vector»—, Rust provides specific structures to wrap them (<mark>Box</mark>, <mark>Rc</mark>, <mark>Arc</mark>, etc.), ensuring that they will be cleaned as soon as possible.</p><p>One of the main features of Rust is a comeback to a simplified version of C structs instead of C++/Java-like classes. There are three main keywords related to structs in Rust: <mark>struct</mark>, <mark>impl</mark> and <mark>trait</mark>. We can define a new struct using the <mark>struct</mark> keyword with the values that it is holding; after defining it, we can add methods with the <mark>impl</mark> keyword. In case we want to describe a common behaviour for several implementations, we can do it with the <mark>trait</mark> keyword, similar to what in other languages is called an <mark>interface</mark>:</p><pre><code>language-rust<br />⁠<br />⁠// We can define a struct for Person<br />⁠// with a name that will be a String<br />⁠struct Person {<br />  name: String,<br />⁠}<br /><br />⁠// We can also define a similar struct, but for a Cat<br />⁠// also with a name that will be a string<br />⁠struct Cat {<br />  name: String,<br />⁠}<br />⁠<br />⁠// Each living being can perform certain actions<br />⁠trait LivingBeingActions {<br />  fn introduce(&amp;self);<br />⁠}<br />⁠<br />⁠// The person can introduce himself verbally<br />⁠impl LivingBeingActions for Person {<br />  fn introduce(&amp;self) {<br />    println!(&quot;- {}: Hi! It&#39;s a pleasure :)&quot;, &amp;self.name);<br />  }<br />⁠}<br />⁠<br />⁠// The can can also introduce himself, except… in cat&#39;s style<br />⁠impl LivingBeingActions for Cat {<br />  fn introduce(&amp;self) {<br />    println!(&quot;- {}: Mrrrrr… Miaaou&quot;, &amp;self.name);<br />  }<br />⁠}<br />⁠<br />⁠// We can instantiate the Person and the Cat,<br />⁠// and then they can introduce themselves<br />⁠fn main() {<br />  let john_doe = Person {<br />    name: String::from(&quot;John Doe&quot;),<br />  };<br />  let grumpy = Cat {<br />    name: String::from(&quot;Grumpy&quot;),<br />  };<br />  john_doe.introduce(); // - John Doe: Hi!, a pleasure :)<br />  grumpy.introduce(); // - Grumpy: Mrrrrr... Miaaou<br />⁠}</code></pre><figcaption>Some Rust syntax: <mark>struct</mark>, <mark>trait</mark>, and <mark>impl</mark>: try me at the <a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2021&amp;gist=c13ea59a730014cd097217940bf7809f" target="_blank">Rust Playground</a>&nbsp;</figcaption><p>This use of structs instead of classes will prevent nested structures, favouring composition instead. Rust will allow us to write code in an object-oriented manner as well as in a functional style, but within a limited frame in both cases. It is perfectly possible to use object-oriented patterns as dependency injection or features as polymorphism, as well as write functional stateless piped code with closures. Both approaches fit naturally, although with some constraints that force the developer to write atomic and readable structures. The resulting code has a somewhat complex syntax, but flat and simple structures which, at the end, make the code easier to read and understand.</p><p>Rust comes with a standard library that provides several functionalities. Among them are the threading tools, which will allow us to write concurrent programs. This, with the help of the compiler, static typing, borrow checker and the advanced pointers will ensure that our multithreaded program is memory safe even in multi-threaded programs.</p><p>An interesting feature of Rust is that it is not coupled with an asynchronous runtime. For this, we will need to bring an external library: a very common option is the Tokio library, that can be found in the Rust <a href="https://crates.io/crates/tokio" target="_blank">official packages repository</a>, although there are other options available.</p><p>The tests are written with the embedded tests suite. It is possible to write both unit tests for each module as well as integration tests for the whole application. Its features are limited but clear following the philosophy of the language.</p><p>Working with Rust coming from Java-like languages is somewhat confusing due to the considerable paradigm shift; of course, once this difficulty is overcome the language writes naturally. It has similarities to common used languages such as C++ and C, but with a cleaner footprint. Given the tools it provides for memory management and generics, it could easily be described as «declarative C».</p><h1>A basic Rust example</h1><p>To demonstrate how a program can be structured in Rust we can create a naive and simple application, just to visualize the main language features.</p><p>Following our previous example, we can develop a program that will ask for a users list from, lets say, a PostgreSQL database. The catch is that we want the list of users in reverse order. </p><p>So we have some different concerns here: </p><ul><li>The <mark>User</mark> itself, which will be a plain model. </li><li>The business logic, which is reversing the order of the retrieved list: this will be a use case. This use case will make use of any retrieval system that complies with a <mark>trait</mark>.</li><li>Finally we will need the system to retrieve data from the PostgreSQL database, which will be a <mark>struct</mark>. To avoid coupling the use case with the PostgreSQL repository we can create a <mark>trait</mark> that all repositories have to comply with. The use case will be able to receive any repository instance that complies with this trait.</li></ul><img src="https://www.api.antoniodiaz.me/media/files/e4e2bb46-c210-4a47-9e84-f45c789fcec1/articles/original/80d4a456-4b25-4b2a-b4b4-3416dcef2ce7.png" data-ratio="0.44" /><figcaption>Structure of our basic application</figcaption><p>Now that we have an idea of our application, let&#39;s implement it. We will omit a few lines of code needed for the program to compile, but the whole example can be seen in the <a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2021&amp;gist=22e033ec941fbc7cab591ce88b56c9f0" target="_blank">Rust Playground</a>.</p><p>First we can create our entity, an <mark>User</mark> with just an <mark>id</mark> field:</p><pre><code>language-rust<br />⁠<br />⁠pub struct User {<br />  pub id: i8,<br />⁠}</code></pre><figcaption>The <mark>User</mark> model</figcaption><p>Now that we have our main model, the next question is what we want to do with it. In other words: the use case to retrieve a reverted list of users. We know that it will need to hold the repository instance, but we don’t know the type: this is a task for a generic type.</p><pre><code>language-rust<br />⁠<br />⁠struct GetUsersRevertedUseCase&lt;T&gt; {<br />  repository: T,<br />⁠}</code></pre><figcaption>Struct for our use case</figcaption><p>Our use case is gathering the type of the repository instance when it is constructed. Let&#39;s create the new method to construct it, for which we can use the <mark>impl</mark> keyword:</p><pre><code>language-rust<br />⁠<br />⁠impl&lt;T: Repository&gt; GetUsersRevertedUseCase&lt;T&gt; {<br />  fn new(repository: T) -&gt; GetUsersRevertedUseCase&lt;T&gt; {<br />    GetUsersRevertedUseCase { repository }<br />  }<br />⁠}</code></pre><figcaption>Implementing <mark>new</mark> for our use case</figcaption><p>⁠One thing to note here is the<mark> &lt;T: Repository&gt;</mark> syntax. We are telling the compiler that <mark>T</mark> will be any struct implementing the <mark>Repository</mark>&nbsp;<mark>trait</mark>, returning error if any other type of instance is passed. Also our new method returns an instance of itself.</p><p>We can think now about the different repositories that this use case may depend on. We know that it will be an asynchronous action, and that it will return a list of users. Lets implement this in a <mark>trait</mark>:</p><pre><code>language-rust<br />⁠<br />⁠trait Repository {<br />  async fn get_users(&amp;self) -&gt; Result&lt;Vec&lt;User&gt;, String&gt;;<br />⁠}</code></pre><figcaption> Trait for our repository</figcaption><p>We have new things here. First, we have the <mark>async</mark> keyword, which makes our function return a <mark>Result</mark> type. This <mark>Result</mark> type is one of the particularities of Rust: it represents the result of an action that can be successful —<mark>Ok(T)</mark>— or error —<mark>Err(K)</mark>—. In our case, if the method is successful, it will return <mark>Ok&lt;Vec&lt;User&gt;&gt;</mark>, which is an array —a <mark>vector</mark> in Rust language— of <mark>User</mark> items; otherwise, if it errors, it will return <mark>Err(String).</mark> For the sake of brevity we won’t return any error, but the <mark>Result</mark> type forces us to take that possibility into account, as we are writing asynchronous code.</p><p>Now we can think about how we will trigger our use case, so let&#39;s implement an execute method for it.</p><pre><code>language-rust<br />⁠<br />⁠impl&lt;T: Repository&gt; GetUsersRevertedUseCase&lt;T&gt; {<br />  […]<br />  async fn execute(&amp;self) -&gt; Result&lt;Vec&lt;User&gt;, String&gt; {<br />    let users = self.repository.get_users().await.unwrap();<br />    let reverted_users: Vec&lt;User&gt; = users.into_iter().rev().collect();<br />    Ok(reverted_users)<br />  }<br />⁠}</code></pre><figcaption> Implementing <mark>execute</mark> for our use case</figcaption><p>We see the <mark>async</mark> syntax, this time awaiting the function of the repo we are calling. We also see the <mark>Result</mark> type again. Everything is familiar. </p><p>As the repository is returning a <mark>Result</mark> —<mark>Ok&lt;T&gt;</mark> or <mark>Err&lt;K&gt;</mark>— type, we need to extract the value —the array of users— to operate with it. We do this with the <mark>unwrap()</mark> function, extracting the value if the operation is successful, or panicking with the error if it&#39;s not.</p><p>We also have some methods operating over the users vector to reverse it: <mark>into_iter</mark>, which turns a vector into an iterable list of items; <mark>rev</mark>, which reverses this iterable list, and <mark>collect</mark>, which returns back the iterable list into a vector. These utility methods belong to <mark>Vec</mark>&nbsp;<mark>struct</mark>, and are embedded into the Rust to manipulate vectors in a functional manner.</p><p>Ok, now we have a use case and an interface for any repository we may pass to it, so we can proceed to create an actual repository for PostgreSQL:</p><pre><code>language-rust<br />⁠<br />⁠impl Repository for PostgreSQLRepository {<br />  async fn get_users(&amp;self) -&gt; Result&lt;Vec&lt;User&gt;, String&gt; {<br />⁠    let duration_secs = Duration::from_secs(2);<br />⁠    sleep(duration_secs);<br />⁠    let user_1 = User { id: 1 };<br />⁠    let user_2 = User { id: 2 };<br />⁠    Ok(vec![user_1, user_2])<br />⁠  }<br />⁠}</code></pre><figcaption> Struct for our  PostgreSQL repository</figcaption><p>We are going to mock the asynchronous behaviour, so we are using two methods of the standard library: <mark>sleep</mark> and <mark>Duration</mark>. <mark>Duration</mark> will return a special time type that can be used by other methods, such as <mark>sleep</mark>; and <mark>sleep</mark> will simply halt execution for the given time. We are just halting our function for two seconds, then instantiating two users, and finally returning a <mark>Vector</mark> holding them.</p><p>We now have all needed components for our program: an <mark>User</mark> entity, the <mark>GetUsersRevertedUseCase</mark>, the interface <mark>Repository</mark> and the actual <mark>PostgreSQLRepository</mark> that implements it. Lets create an entry point and make use of all these elements:</p><pre><code>language-rust<br />⁠<br />⁠#[tokio::main]<br />⁠async fn main() {<br />⁠  let repository = PostgreSQLRepository;<br />⁠  let use_case = GetUsersRevertedUseCase::new(repository);<br />⁠  let users = use_case.execute().await.unwrap();<br />⁠  println!(&quot;{:#?}&quot;, users);<br />⁠}</code></pre><figcaption>Entry point for our program</figcaption><p>As we are running asynchronous code we will need an asynchronous runtime: thus, we can call the macro <mark>#[tokio:main]</mark>. Then we just create an instance of the repository, we construct our use case injecting the repository, and execute it awaiting. The result will be a vector of users in reverse order:</p><pre><code>language-rust<br />⁠<br />⁠[<br />⁠  User {<br />⁠    id: 2,<br />⁠  },<br />⁠  User {<br />⁠    id: 1,<br />⁠  },<br />⁠]</code></pre><figcaption>Result: a reverted list of users</figcaption><p>As mentioned above this code is available in the <a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2021&amp;gist=22e033ec941fbc7cab591ce88b56c9f0" target="_blank">Rust Playground</a>, where we can compile and run it.</p><h1>Conclusion</h1><p>Rust is not a straightforward language. Study and some patience is required to understand both the basic syntax and the underlying features that it provides; it is also young, and its ecosystem has to evolve. But it is promising.</p><p>It is in performance demanding tasks where the language fits perfectly. For general web development, where rapid prototyping with agile workflows is a requirement, interpreted languages such as Python or TypeScript may be more suitable; but in cases where memory leaks may cause spikes and performance issues in server usage, Rust is a much better option.</p><p>The current acceptance of Rust within the industry is very limited, but the Rust foundation is supported by Google, Microsoft, AWS, Huawei and Mozilla: there is a need for such a performant language, and we will probably see how it is introduced in the following years. There are difficulties though: the funding companies will try to <a href="https://news.ycombinator.com/item?id=28513130" target="_blank">influence</a> Rust to make it evolve fitting their particular needs, and there are strong <a href="https://blog.rust-lang.org/inside-rust/2021/11/25/in-response-to-the-moderation-team-resignation.html" target="_blank">disagreements</a> among the internal Rust development teams. But the language fits so well into the aforementioned tasks that it will be worthwhile to follow its evolution and integration into the web industry.</p><p>In conclusion: it is possible and desirable to use Rust in specific contexts where performance and assurance is required.</p></p>]]></description></item><item><title>Notes on Merge sort</title><pubDate>Tue, 20 Jan 1970 00:00:00 GMT</pubDate><guid isPermaLink="true">https://www.antoniodiaz.me/en/blog/3</guid><description><![CDATA[<p><p>Some basic notes about Merge Sort algorithm.</p><h2>Description</h2><p>Recursive algorithm based on the divide and conquer strategy. It has two main components: </p><ul><li>A function that splits the a list recursively until it receives a single item.</li><li>A «merge» function that merges two already sorted lists into a combined sorted one.</li></ul><h2>⁠Time complexity⁠</h2><img src="https://www.api.antoniodiaz.me/media/files/e4e2bb46-c210-4a47-9e84-f45c789fcec1/articles/original/0830c9a4-6562-4e42-bfcb-c2ffda99a920.png" data-ratio="0.55" /><figcaption>Time complexity for Merge Sort</figcaption><h2>Pseudocode</h2><div><div class="math">Input: A = [A_1, A_2, …, A_n];\\Output: B = [B_1, B_2, …, B_n];\\[10pt]⁠function \enspace MergeSort(A)⁠\\\quad n \leftarrow length(A);⁠\\\quad if \space n \leqslant then:⁠\\\quad\quad return \space A;\\⁠\quad else:⁠\\\quad\quad l \leftarrow [A_1, …, A_{n/2}];⁠⁠\\\quad\quad r \leftarrow [A_{(n/2)+1}, …, A_n];⁠\\\quad\quad L \leftarrow MergeSort(l);⁠⁠\\\quad\quad R \leftarrow MergeSort(r);⁠⁠⁠\\\quad\quad B \leftarrow Merge(L, R);⁠\\\quad\quad return \space B;⁠⁠\\\quad end \space if;⁠⁠\\end \space function;\\[10pt]⁠function Merge(L, R)\\⁠\quad n \leftarrow length(L) + length(R);\\⁠\quad B \leftarrow [\space];\\⁠\quad i \leftarrow 0;\\⁠\quad j \leftarrow 0;\\⁠\quad for \space k \leftarrow 0 \space to \space n \space do:\\⁠\qquad if \space i \leqslant length(L) \space and \space j \leqslant length(R) \space then:\\⁠\qquad\quad if \space L[i] \leqslant R[j] \space then:\\⁠\qquad\qquad B[k] \leftarrow L[i];\\⁠\qquad\qquad i \leftarrow i + 1;\\⁠⁠\qquad\quad else \space if \space L[i] \text{\textgreater} R[j] \space then:\\⁠\qquad\qquad B[k] \leftarrow R[j];\\⁠\qquad\qquad j \leftarrow j + 1;\\⁠⁠\qquad\quad end \space if;\\⁠⁠\qquad else \space if \space i + 1 \leqslant length(L) \space then:\\⁠⁠\qquad\quad B[k] \leftarrow L[i];\\⁠\qquad\quad i \leftarrow i + 1;\\⁠⁠⁠\qquad else \space if \space j + 1 \leqslant length(R) \space then:\\⁠⁠\qquad\quad B[k] \leftarrow R[j];\\⁠\qquad\quad j \leftarrow j + 1;\\⁠⁠⁠⁠\qquad end \space if;\\⁠⁠⁠⁠⁠\quad end \space for;\\⁠\quad return \space B;\\end \space function;⁠</div></div><p>&nbsp;</p><h2>Implementation in Rust</h2><pre><code>language-rust<br />⁠<br />pub fn merge_sorted_arrays(left: Vec&lt;i32&gt;, right: Vec&lt;i32&gt;) -&gt; Vec&lt;i32&gt; {<br />⁠  let left_length = left.len();<br />⁠  let right_length = right.len();<br />⁠<br />⁠  // Final array will be the size of both provided arrays<br />⁠  let mut sorted_items = vec![0; left_length + right_length];<br />⁠<br />⁠  let mut i = 0;<br />⁠  let mut j = 0;<br />⁠<br />⁠  // Iterate over the array that we will fill with items either <br />⁠  // in left or right arrays<br />⁠  for k in 0..sorted_items.len() {<br />⁠    // If neither &quot;i&quot; and &quot;j&quot; pointers did reach the limit <br />⁠    // of their respective arrays<br />⁠    if i + 1 &lt;= left.len() &amp;&amp; j + 1 &lt;= right.len() {<br />⁠      // Decide between current item in left array and current item <br />⁠      // in right array which one will be next in final array<br />⁠      if left[i] &lt;= right[j] {<br />⁠        sorted_items[k] = left[i];<br />⁠        i = i + 1;<br />⁠      } else if left[i] &gt; right[j] {<br />⁠        sorted_items[k] = right[j];<br />⁠        j = j + 1;<br />⁠      }<br />⁠    } else if i + 1 &lt;= left.len() {<br />⁠      // If only &quot;i&quot; pointer didnt reach the limit —but &quot;j&quot; did—<br />⁠      sorted_items[k] = left[i];<br />⁠      i = i + 1;<br />⁠    } else if j + 1 &lt;= right.len() {<br />⁠      // If only &quot;j&quot; pointer didnt reach the limit —but &quot;i&quot; did—<br />⁠      sorted_items[k] = right[j];<br />⁠      j = j + 1;<br />⁠    }<br />⁠  }<br />⁠<br />⁠  sorted_items<br />⁠}<br />⁠<br />⁠pub fn sort_array(unsorted_array: &amp;Vec&lt;i32&gt;) -&gt; Vec&lt;i32&gt; {<br />⁠  let n = unsorted_array.len();<br />⁠  if n &lt;= 1 {<br />⁠    // Base case: if input has length of one it is already sorted, <br />⁠    // return it<br />⁠    let sorted_array = unsorted_array.to_vec();<br />⁠    sorted_array<br />⁠  } else {<br />⁠    // If input has length bigger than two, then:println!<br />⁠    // 1. Split it<br />⁠    let (left, right) = unsorted_array.split_at(n / 2);<br />⁠    let left_vec = left.to_vec();<br />⁠    let right_vec = right.to_vec();<br />⁠<br />⁠    // 2. Sort it recursively<br />⁠    let left_sorted = sort_array(&amp;left_vec);<br />⁠    let right_sorted = sort_array(&amp;right_vec);<br />⁠    let sorted_array_1 = merge_sorted_arrays(left_sorted, right_sorted);<br />⁠    sorted_array_1<br />⁠  }<br />⁠}<br />⁠<br />⁠fn main() {<br />⁠  let unsorted_array: Vec&lt;i32&gt; = vec![2, 1, 4, 3];<br />⁠  let sorted_array = sort_array(&amp;unsorted_array);<br />⁠  println!(&quot;unsorted_array: {:?}&quot;, unsorted_array);<br />⁠  println!(&quot;sorted_array: {:?}&quot;, sorted_array);<br />⁠}<br />⁠<br />⁠#[cfg(test)]<br />⁠mod tests {<br />⁠  use super::*;<br />⁠<br />⁠  #[test]<br />⁠  fn works_with_sorted_arrays() {<br />⁠    let unsorted_array = vec![1, 2];<br />⁠    let sorted_array = sort_array(&amp;unsorted_array);<br />⁠    let expected_result = vec![1, 2];<br />⁠    assert_eq!(expected_result, sorted_array);<br />⁠  }<br />⁠<br />⁠  #[test]<br />⁠  fn works_with_simple_unsorted_array() {<br />⁠    let unsorted_array = vec![2, 1];<br />⁠    let sorted_array = sort_array(&amp;unsorted_array);<br />⁠    let expected_result = vec![1, 2];<br />⁠    assert_eq!(expected_result, sorted_array);<br />⁠  }<br />⁠<br />⁠  #[test]<br />⁠  fn works_with_simple_uneven_lenght_arrays() {<br />⁠    let unsorted_array = vec![2, 1, 3];<br />⁠    let sorted_array = sort_array(&amp;unsorted_array);<br />⁠    let expected_result = vec![1, 2, 3];<br />⁠    assert_eq!(expected_result, sorted_array);<br />⁠  }<br />⁠<br />⁠  #[test]<br />⁠  fn it_works_with_sorted_arrays() {<br />⁠    let left = vec![1, 2];<br />⁠    let right = vec![3, 4];<br />⁠    let merged = merge_sorted_arrays(left, right);<br />⁠    let expected_result = vec![1, 2, 3, 4];<br />⁠    assert_eq!(expected_result, merged);<br />⁠  }<br />⁠<br />⁠  #[test]<br />⁠  fn it_works_with_splits() {<br />⁠    let left = vec![3, 4];<br />⁠    let right = vec![1, 2];<br />⁠    let merged = merge_sorted_arrays(left, right);<br />⁠    let expected_result = vec![1, 2, 3, 4];<br />⁠    assert_eq!(expected_result, merged);<br />⁠  }<br />⁠<br />⁠  #[test]<br />⁠  fn it_works_with_uneven_length_lists() {<br />⁠    let left = vec![3, 4, 5];<br />⁠    let right = vec![1, 2];<br />⁠    let merged = merge_sorted_arrays(left, right);<br />⁠    let expected_result = vec![1, 2, 3, 4, 5];<br />⁠    assert_eq!(expected_result, merged);<br />⁠  }<br />⁠<br />⁠  #[test]<br />⁠  fn it_works_with_single_item_lists() {<br />⁠    let left = vec![3];<br />⁠    let right = vec![1];<br />⁠    let merged = merge_sorted_arrays(left, right);<br />⁠    let expected_result = vec![1, 3];<br />⁠    assert_eq!(expected_result, merged);<br />⁠  }<br />⁠}</code></pre><figcaption>Rust implementation, run me at Rust <a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2021&amp;gist=1aee4409d31789101bcaba255c7b0d11" target="_blank">Playground</a>&nbsp;</figcaption></p>]]></description></item><item><title>On closures in Rust</title><pubDate>Tue, 20 Jan 1970 00:00:00 GMT</pubDate><guid isPermaLink="true">https://www.antoniodiaz.me/en/blog/4</guid><description><![CDATA[<p><p>When I went through the exercises on <a href="https://doc.rust-lang.org/book/" target="_blank">The Rust Programming Language</a> book I remember finding the <a href="https://doc.rust-lang.org/book/ch13-01-closures.html#storing-closures-using-generic-parameters-and-the-fn-traits" target="_blank">example about closures</a> interesting. The provided code was just about implementing a naive cache system to avoid repeated expensive calculations for previously passed inputs. It looked like this:</p><pre><code>language-rust<br />⁠<br />// Struct accepting a Generic, which has <br />⁠// to be a function with an u32 as parameter<br />⁠// and returning an u32 value<br />⁠pub struct Cacher&lt;T: Fn(u32) -&gt; u32&gt; {<br />⁠  pub calculation: T,<br />⁠  pub value: Option&lt;u32&gt;,<br />⁠}<br />⁠<br />⁠// Implementation for Cacher, where we add our behaviour<br />⁠impl&lt;T: Fn(u32) -&gt; u32&gt; Cacher&lt;T&gt; {<br />⁠  // Instantiate the struct with a function, that will be<br />⁠  // stored within the struct scope as a closure<br />⁠  pub fn new(calculation: T) -&gt; Cacher&lt;T&gt; {<br />⁠    Cacher {<br />⁠      calculation,<br />⁠      value: None,<br />⁠    }<br />⁠  }<br />⁠<br />⁠  // Getter to retrieve the current value<br />⁠  pub fn value(&amp;mut self, input: u32) -&gt; u32 {<br />⁠    match self.value {<br />⁠      Some(value) =&gt; value,<br />⁠      None =&gt; {<br />⁠        let value = (self.calculation)(input);<br />⁠        self.value = Some(value);<br /><br />⁠⁠        value<br />⁠      }<br />⁠    }<br />⁠  }<br />⁠}<br />⁠</code></pre><figcaption>Cacher implementation with a closure and generics</figcaption><p>Easy enough. If <mark>value</mark> is empty the cacher will calculate the result and return it; otherwise, it will return the existing value. But there is a catch: if we run the <mark>Cacher::value()</mark> method twice with different values, it will return the first one that was stored, which we can demonstrate with this test:</p><pre><code>language-rust<br />⁠<br />#[cfg(test)]<br />⁠mod tests {<br />⁠  use super::*;<br />⁠  use ::std::thread;<br />⁠  use ::std::time::Duration;<br />⁠<br />⁠  #[test]<br />⁠  fn call_with_different_values() {<br />⁠    fn my_function(num: u32) -&gt; u32 {<br />⁠   ⁠   num<br />⁠    }<br />⁠<br />⁠    let mut cacher = Cacher::new(my_function);<br />⁠<br />⁠    let value_1 = cacher.value(1);<br />⁠    let value_2 = cacher.value(2);<br />⁠<br />⁠    assert_eq!(value_1, 1);<br />⁠    assert_eq!(value_2, 2);<br />⁠  }<br />⁠}</code></pre><figcaption>Failing test for our cacher: run it here in the <a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2021&amp;gist=1d80b54ca923a8c020d9ef79473b2b21" target="_blank">playground</a>&nbsp;</figcaption><p>The issue is that we are storing the value within <mark>Cacher.value</mark> directly, so once it is calculated the same value will be returned the rest of the times. What we need is a structure that can store the resulting values in relation to the inputs, and one with fast search and insert times. We need a Hashmap.</p><p>So instead of using <mark>value</mark> as an <mark>Option&lt;u32&gt;</mark> to store a single value, we can use <mark>values</mark> with an <mark>std::collections::HashMap</mark>, as follows:</p><pre><code>language-rust<br />⁠<br />use std::collections::HashMap; <br />⁠<br />⁠struct Cacher&lt;T: Fn(u32) -&gt; u32&gt; {<br />⁠  calculation: T,<br />⁠  values: HashMap&lt;u32, u32&gt;,<br />⁠}</code></pre><p>Our hashmap will have <mark>u32</mark> keys with <mark>u32</mark> values. We can now proceed to instantiate it on our constructor:</p><pre><code>language-rust<br />⁠<br />fn new(calculation: T) -&gt; Cacher&lt;T&gt; {<br />⁠  Cacher {<br />⁠    calculation,<br />⁠    values: HashMap::new(),<br />⁠  }<br />⁠}</code></pre><p>And finally create or getter/setter method with the match pattern that will decide what to do:</p><pre><code>language-rust<br />⁠<br />fn value(&amp;mut self, input: u32) -&gt; u32 {<br />⁠  match self.values.get(&amp;input) {<br />⁠    Some(value) =&gt; *value,<br />⁠    None =&gt; {<br />⁠      let value = (self.calculation)(input);<br />⁠      self.values.insert(input, value);<br />⁠<br />⁠      value<br />⁠    }<br />⁠  }<br />⁠}</code></pre><p>So if the input already exists in <mark>self.values</mark> —<mark>self.values.get(&amp;input)</mark>—, retrieve it; otherwise, set into <mark>self.values</mark> both the input and value as key/value pair. Notice that when a given value exists —<mark>Some(value)</mark>—, we retrieve it as <mark>*value</mark>: that&#39;s because what we store is the reference <mark>&amp;input</mark>, so we need to dereference it to retrieve its actual value. If we remove the dereference we will get the corresponding error notifying that Rust <mark>expected `u32`, found `&amp;u32`</mark>.</p><pre><code>language-none<br />⁠<br />⣿ Standard Error<br />⁠<br />⁠Compiling playground v0.0.1 (/playground)<br />⁠error[E0308]: mismatched types<br />⁠  --&gt; src/lib.rs:18:28<br />⁠   |<br />⁠16 |     pub fn value(&amp;mut self, input: u32) -&gt; u32 {<br />⁠   |                    --- expected `u32` because of return type<br />⁠17 |         match self.values.get(&amp;input) {<br />⁠18 |             Some(value) =&gt; value,<br />⁠   |                            ^^^^^ expected `u32`, found `&amp;u32`<br />⁠   |<br />⁠help: consider dereferencing the borrow<br />⁠   |<br />⁠18 |             Some(value) =&gt; *value,<br />⁠   |                            +</code></pre><p>Finally note the parenthesis on <mark>(self.calculation)(input)</mark>. They seem unnecesary, but actually they are. Lets break things first and remove them:</p><pre><code>language-none<br />⁠<br />⣿ Standard Error<br />⁠<br />Compiling playground v0.0.1 (/playground)<br />⁠error[E0599]: no method named `calculation` found for mutable reference <br />⁠`&amp;mut Cacher&lt;T&gt;` in the current scope<br />⁠  --&gt; src/lib.rs:20:34<br />⁠   |<br />⁠20 |                 let value = self.calculation(input);<br />⁠   |                                  ^^^^^^^^^^^ field, not a method<br />⁠   |<br />⁠help: to call the function stored in `calculation`, surround the field access <br />⁠with parentheses<br />⁠   |<br />⁠20 |                 let value = (self.calculation)(input);<br />⁠   |                             +                +</code></pre><p>As previously, Rust informs us both about the error and possible fix. It is intelligent enough to identify that we are trying to call the function we stored as a closure, thus the need of the parenthesis. If we restore them and <a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2021&amp;gist=d5dcba3c9d3eca09294cbdea3c108a9b" target="_blank">try to run our test</a> again, this what we get:</p><pre><code>language-none<br />⁠<br />running 1 test<br />⁠test tests::call_with_different_values ... ok</code></pre><p>Fantastic, it is passing \(^O^)/. <br />⁠<br />⁠Of course this is something really simple, but I like the example because it has a reference and a dereference, a structure from <mark>std</mark> , a closure, a generic with a bound type and a <mark>match</mark> pattern. You can&#39;t ask for more!<br />⁠</p></p>]]></description></item><item><title>Dependency inversion in Rust</title><pubDate>Tue, 20 Jan 1970 00:00:00 GMT</pubDate><guid isPermaLink="true">https://www.antoniodiaz.me/en/blog/6</guid><description><![CDATA[<p><p>Given a struct <mark>MyStruct</mark> living within module <mark>my_struct</mark>, and a trait <mark>Feature</mark> living in the module <mark>my_feature</mark>, it is required that <mark>MyStruct</mark> holds different implementations of the trait <mark>Feature</mark> without depending on these implementations.</p><p>Our goal will be to tell <mark>MyStruct</mark> that it may accept any struct that implements <mark>Feature</mark> via <mark>new()</mark> method as parameter.</p><p>⁠In other languages —mostly with structural typing— the footprint of this <mark>new()</mark> method would look like this:</p><pre><code>language-rust<br />⁠<br />⁠fn new(feature: Feature) -&gt; MyStruct;</code></pre><p>This won&#39;t work in Rust, as it can&#39;t infere the size of <mark>Feature</mark> at compile time.</p><p>But this may be achieved via two different strategies: </p><ul><li>Using generics</li><li>Using trait objects</li></ul><h2>Dependency inversion with generics</h2><p>It is possible to let the compiler pass the type of <mark>Feature</mark> as a generic. </p><p>A first step would be to define <mark>Feature</mark> trait within <mark>feature</mark> module:</p><pre><code>language-rust<br />⁠<br />⁠⁠mod feature {<br />⁠  pub trait Feature {<br />⁠    fn action(&amp;self) -&gt; String;<br />⁠  }<br />⁠}</code></pre><figcaption><mark>Feature</mark> module</figcaption><p>Within <mark>my_struct</mark> module would live <mark>MyStruct</mark>. It would receive any generic of type <mark>Feature</mark>, which can be seen in <mark>impl &lt;T: Feature&gt;...</mark>.</p><p><mark>MyStruct</mark> will then receive <mark>T</mark> as generic; now it will be possible to type <mark>feature</mark> parameter as <mark>T</mark>.</p><pre><code>language-rust<br />⁠<br />⁠⁠mod my_struct {<br />⁠  use super::feature::Feature;<br />⁠<br />⁠  pub struct MyStruct&lt;T&gt; {<br />⁠    feature: T,<br />⁠  }<br />⁠<br />⁠  impl&lt;T: Feature&gt; MyStruct&lt;T&gt; {<br />⁠    pub fn new(feature: T) -&gt; MyStruct&lt;T&gt; {<br />⁠      MyStruct { feature }<br />⁠    }<br />⁠<br />⁠    pub fn action(&amp;self) -&gt; String {<br />⁠      self.feature.action()<br />⁠    }<br />⁠  }<br />⁠}</code></pre><figcaption><mark>MyStruct</mark> module</figcaption><p>The different implementations of <mark>Feature</mark> would live in different modules:</p><pre><code>language-rust<br />⁠<br />⁠mod feature_implementation01 {<br />⁠  use super::feature::Feature;<br />⁠<br />⁠  pub struct FeatureImplementation01;<br />⁠<br />⁠  impl Feature for FeatureImplementation01 {<br />⁠    fn action(&amp;self) -&gt; String {<br />⁠      String::from(&quot;Feature 01 - with generics&quot;)<br />⁠    }<br />⁠  }<br />⁠}<br />⁠</code></pre><figcaption>First implementation of <mark>Feature</mark></figcaption><pre><code><br />language-rust<br />⁠<br />⁠⁠mod feature_implementation02 {<br />⁠  use super::feature::Feature;<br />⁠<br />⁠  pub struct FeatureImplementation02;<br />⁠<br />⁠  impl Feature for FeatureImplementation02 {<br />⁠    fn action(&amp;self) -&gt; String {<br />⁠      String::from(&quot;Feature 02 - with generics&quot;)<br />⁠    }<br />⁠  }<br />⁠}</code></pre><figcaption>Second implementation of <mark>Feature</mark></figcaption><p>Finally the client code would consume this logic:</p><pre><code><br />language-rust<br />⁠<br />⁠⁠pub fn main() {<br />⁠  use feature_implementation01::FeatureImplementation01;<br />⁠  use feature_implementation02::FeatureImplementation02;<br />⁠  use my_struct::MyStruct;<br />⁠<br />⁠  let feature_implementation_01_instance = FeatureImplementation01;<br />⁠  // If required, it is possible to pass the type of <br />⁠  // the implementation into the generic with turbofish syntax<br />⁠  let my_struct = <br />⁠    MyStruct::&lt;FeatureImplementation01&gt;::new(<br />⁠      feature_implementation_01_instance<br />⁠    );<br />⁠  let result = my_struct.action();<br />⁠  println!(&quot;{:#?}&quot;, result);<br />⁠<br />⁠  ⁠// If required, it is possible to pass the type of <br />⁠  // the implementation into the generic with turbofish syntax<br />⁠  let feature_implementation_02_instance = FeatureImplementation02;<br />⁠  let my_struct = <br />⁠    MyStruct::&lt;FeatureImplementation01&gt;::new(<br />⁠      feature_implementation_02_instance<br />⁠    );<br />⁠  let result = my_struct.action();<br />⁠  println!(&quot;{:#?}&quot;, result);<br />⁠}</code></pre><figcaption>Run in <a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2021&amp;gist=33466215ba9d6b644ec56e258922d756" target="_blank"><strong>Rust playground</strong></a>&nbsp;</figcaption><p>It is important to note that when <mark>MyStruct::new</mark> is called, it is receiving the type of the struct implementing <mark>Feature</mark> with the turbofish syntax:</p><pre><code>language-rust<br />⁠<br />⁠let my_struct = MyStruct::&lt;FeatureImplementation01&gt;::new(<br />⁠<span style="width: 10px; display: inline-block"></span><span style="width: 10px; display: inline-block"></span>  feature_implementation_01_instance<br />⁠);</code></pre><figcaption>Instantiating <mark>MyStruct</mark> injecting an instance implementing <mark>Feature</mark></figcaption><p>⁠Rust compiler may be able to infere it. This is the case with this code: if we remove <mark>::&lt;FeatureImplementation01&gt;</mark>, the compiler will be able to find out which type is passed; but it is not always the case, and sometimes the developer may be required to pass it manually.<br /></p><h2>⁠With Smart pointers</h2><p>Rust provides several smart pointers for dinamically sized structures. The obvious choice here is <mark>Box</mark>.<br />The required changes to achieve this will hapen only on <mark>my_struct</mark> module and within the client code, as seen below.<br />It is required to remove the generics on <mark>MyStruct</mark>; the issue then will be that <mark>feature</mark> is typed as the trait <mark>Feature</mark>: but the size of structs implementing this trait may vary. <br />⁠This can be solved by wrapping <mark>Feature</mark> within <mark>Box&lt;dyn Feature&gt;</mark>⁠, telling the compiler to send this struct into the heap, which is dinamically sized. To be explicit about traits being dinamically dispatched Rust forces us to use the <mark>dyn</mark> keyword.</p><pre><code>language-rust<br />⁠<br />⁠mod my_struct {<br />⁠  use super::feature::Feature;<br />⁠<br />⁠  pub struct MyStruct {<br />⁠    feature: Box&lt;dyn Feature&gt;,<br />⁠  }<br />⁠<br />⁠  impl MyStruct {<br />⁠    pub fn new(feature: Box&lt;dyn Feature&gt;) -&gt; MyStruct {<br />⁠      MyStruct { feature }<br />⁠    }<br />⁠<br />⁠    pub fn action(&amp;self) -&gt; String {<br />⁠      self.feature.action()<br />⁠    }<br />⁠  }<br />⁠}</code></pre><figcaption>Typing feature as <mark>Box&lt;dyn Feature&gt;</mark></figcaption><p>The client code will change as well, as it requires to wrap the feature instance within a <mark>Box</mark> instance:</p><pre><code>language-rust<br />⁠<br />⁠fn main() {<br />⁠  use feature_implementation01::FeatureImplementation01;<br />⁠  use feature_implementation02::FeatureImplementation02;<br />⁠  use my_struct::MyStruct;<br />⁠<br />⁠  let feature_implementation_01_instance = FeatureImplementation01;<br />⁠  let my_struct = MyStruct::new(Box::new(feature_implementation_01_instance));<br />⁠  let result = my_struct.action();<br />⁠  println!(&quot;{:#?}&quot;, result);<br />⁠<br />⁠  let feature_implementation_02_instance = FeatureImplementation02;<br />⁠  let my_struct = MyStruct::new(Box::new(feature_implementation_02_instance));<br />⁠  let result = my_struct.action();<br />⁠  println!(&quot;{:#?}&quot;, result);<br />⁠}</code></pre><figcaption>Run in <a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2021&amp;gist=2f727ee1f529d27b3dabd51c7f849393" target="_blank"><strong>Rust Playground</strong></a>&nbsp;</figcaption><p>Now, lets say <mark>MyStruct</mark> makes use of <mark>MyService</mark>, which at the same time requires the feature instance hold within its struct.</p><pre><code>language-rust<br />⁠<br />⁠mod my_service {<br />⁠  use super::feature::Feature;<br />⁠<br />⁠  pub struct MyService {<br />⁠    feature: Box&lt;dyn Feature&gt;,<br />⁠  }<br />⁠<br />⁠  impl MyService {<br />⁠    pub fn new(feature: Box&lt;dyn Feature&gt;) -&gt; MyService {<br />⁠      MyService { feature }<br />⁠    }<br />⁠  }<br />⁠}</code></pre><figcaption><mark>MyService</mark>, which requires a <mark>Feature</mark> instance</figcaption><pre><code>language-rust<br />⁠<br />⁠mod my_struct {<br />⁠  use super::feature::Feature;<br />⁠  use super::my_service::MyService;<br />⁠<br />⁠  pub struct MyStruct {<br />⁠    feature: Box&lt;dyn Feature&gt;,<br />⁠  }<br />⁠<br />⁠  impl MyStruct {<br />⁠    pub fn new(feature: Box&lt;dyn Feature&gt;) -&gt; MyStruct {<br />⁠      MyStruct { feature }<br />⁠    }<br />⁠<br />⁠    pub fn action(self) -&gt; String {<br />⁠      let my_service = MyService::new(self.feature);<br />⁠      println!(&quot;{}&quot;, my_service.action());<br />⁠<br />⁠      self.feature.action().to_owned()<br />⁠    }<br />⁠  }<br />⁠}</code></pre><figcaption><mark>MyStruct</mark> making use —and depending on— of <mark>MyService</mark></figcaption><p>Now the compiler returns an error, as <mark>MyService</mark> is borrowing <mark>self.feature</mark>:</p><pre><code>language-none<br />⁠<br />⁠⁠error[E0382]: borrow of moved value: `self.feature`<br />⁠  --&gt; src/with_box.rs:25:7<br />⁠   |<br />⁠21 |       let my_service = MyService::new(self.feature);<br />⁠   |                                       ------------ value moved here<br />⁠...<br />⁠25 |       self.feature.action().to_owned()<br />⁠   |       ^^^^^^^^^^^^^^^^^^^^^ value borrowed here after move</code></pre><figcaption>Error when consuming <mark>self.feature</mark></figcaption><p>When passing <mark>self.feature</mark> to <mark>MyService</mark> it is consumed, so it wont be available after this line. A solution would be to <mark>clone()</mark> it; but the compiler will return a new error:</p><pre><code>language-none<br />⁠<br />⁠error[E0599]: the method `clone` exists for struct <br />⁠   `Box&lt;(dyn with_box::feature::Feature + &#39;static)&gt;`, <br />⁠   but its trait bounds were not satisfied<br />⁠   --&gt; src/with_box.rs:21:52<br />⁠    |<br />⁠2   |     pub trait Feature {<br />⁠    |     -----------------<br />⁠    |     |<br />⁠    |     doesn&#39;t satisfy `dyn with_box::feature::Feature: Clone`<br />⁠    |     doesn&#39;t satisfy `dyn with_box::feature::Feature: Sized`<br />⁠...<br />⁠21  |         let my_service = MyService::new(self.feature.clone());<br />⁠    |                                                      ^^^^^ method <br />⁠                cannot be called on <br />⁠                `Box&lt;(dyn with_box::feature::Feature + &#39;static)&gt;` <br />⁠                due to unsatisfied trait bounds</code></pre><p>The trait <mark>Box</mark> doesnt implement <mark>Clone</mark>. It would be possible to implement <mark>Clone</mark> for <mark>Box&lt;dyn Feature&gt;</mark>, but there is a simpler solution: use the <mark>Rc</mark> pointer instead of <mark>Box</mark>.</p><pre><code>language-rust<br />⁠<br />⁠⁠mod my_struct {<br />⁠  use super::feature::Feature;<br />⁠  use super::my_service::MyService;<br />⁠  use std::rc::Rc;<br />⁠<br />⁠  pub struct MyStruct {<br />⁠    feature: Rc&lt;dyn Feature&gt;,<br />⁠  }<br />⁠<br />⁠  impl MyStruct {<br />⁠    pub fn new(feature: Rc&lt;dyn Feature&gt;) -&gt; MyStruct {<br />⁠      MyStruct { feature }<br />⁠    }<br />⁠<br />⁠    pub fn action(self) -&gt; String {<br />⁠      let my_service = MyService::new(self.feature.clone());<br />⁠      println!(&quot;{}&quot;, my_service.action());<br />⁠<br />⁠      self.feature.action().to_owned()<br />⁠    }<br />⁠  }<br />⁠}</code></pre><figcaption>Run in <a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2021&amp;gist=7674212c892bf195a5881dc401108531" target="_blank"><strong>Rust playground</strong></a>&nbsp;</figcaption><p><mark>Rc</mark> implements <mark>Clone</mark>, so we can call it over <mark>self.feature</mark>.</p><p>A last case should be taken into account: the code may be asynchronous; but <mark>Rc</mark> is not thread safe. </p><p>The following examples will make use of <a href="https://crates.io/crates/tokio" target="_blank">Tokio</a> as async runtime as well as <a href="https://crates.io/crates/async-trait" target="_blank">async_trait</a> to be able to create traits with asynchronous methods.<br />⁠<br />For example, if we require <mark>MyStruct</mark> to implement a trait <mark>MyStructTrait</mark>, the compiler will warn that both <mark>MyStructTrait</mark> and <mark>Feature</mark> should implement <mark>Send + Sync</mark> :</p><pre><code>language-rust<br />⁠<br />⁠mod my_struct {<br />⁠  use super::feature::Feature;<br />⁠  use async_trait::async_trait;<br />⁠  use std::rc::Rc;<br />⁠<br />⁠  pub struct MyStruct {<br />⁠    feature: Rc&lt;dyn Feature&gt;,<br />⁠  }<br />⁠<br />⁠  #[async_trait]<br />⁠  pub trait MyStructTrait: Send {<br />⁠    fn new(feature: Rc&lt;dyn Feature&gt;) -&gt; Self;<br />⁠    async fn action(&amp;self) -&gt; Result&lt;String, String&gt;;<br />⁠  }<br />⁠<br />⁠  #[async_trait]<br />⁠  impl MyStructTrait for MyStruct {<br />⁠    fn new(feature: Rc&lt;dyn Feature&gt;) -&gt; Self {<br />⁠      MyStruct { feature }<br />⁠    }<br />⁠<br />⁠    async fn action(&amp;self) -&gt; Result&lt;String, String&gt; {<br />⁠      self.feature.action().await<br />⁠    }<br />⁠  }<br />⁠}</code></pre><figcaption>Async code using <mark>Rc</mark></figcaption><pre><code>language-none<br />⁠<br />⁠error: future cannot be sent between threads safely<br />⁠  --&gt; src/with_arc.rs:31:54<br />⁠   |<br />⁠31 |       async fn action(&amp;self) -&gt; Result&lt;String, String&gt; {<br />⁠   |  ______________________________________________________^<br />⁠32 | |       self.feature.action().await<br />⁠33 | |     }<br />⁠   | |_____^ future created by async block is not `Send`</code></pre><figcaption>Error on async code with <mark>Rc</mark></figcaption><p>It is possible to tell the compiler to extend both <mark>Feature</mark> and <mark>MyStructTrait</mark> with <mark>Send + Sync</mark>; there will be another obstacule though: <mark>x cannot be sent between threads safely</mark>.</p><pre><code>language-none<br />⁠<br />⁠error[E0277]: `Rc&lt;(dyn with_arc::feature::Feature + &#39;static)&gt;` <br />⁠  cannot be sent between threads safely<br />⁠  --&gt; src/with_arc.rs:26:8<br />⁠   |<br />⁠26 |   impl MyStructTrait for MyStruct {<br />⁠   |        ^^^^^^^^^^^^^ `Rc&lt;(dyn with_arc::feature::Feature + <br />⁠                          &#39;static)&gt;<br />⁠       ` cannot be sent between threads safely</code></pre><figcaption>Error when implementing <mark>Send + Sync</mark></figcaption><p>The pointer <mark>Rc</mark> is useful on sync code, but is not thread safe: luckily for this Rust provides <mark>Arc</mark>, which, as per docs: «... provides shared ownership of a value of type <mark>T</mark>, allocated in the heap. […] Unlike <mark>Rc&lt;T&gt;</mark>, <mark>Arc&lt;T&gt;</mark> uses atomic operations for its reference counting. This means that it is thread-safe.»</p><p>Using <mark>Arc</mark> has more memory consumption than <mark>Rc</mark>, but for this case is negligible. And as implements <mark>Clone</mark> it will be possible to perform <mark>self.feature.clone()</mark> in order to pass it to <mark>Service</mark>.</p><pre><code>⁠language-rust<br />⁠<br />⁠mod my_struct {<br />⁠  use super::feature::Feature;<br />⁠  use async_trait::async_trait;<br />⁠  use std::sync::Arc;<br />⁠<br />⁠  pub struct MyStruct {<br />⁠    feature: Arc&lt;dyn Feature&gt;,<br />⁠  }<br />⁠<br />⁠  #[async_trait]<br />⁠  pub trait MyStructTrait: Send + Sync {<br />⁠    fn new(feature: Arc&lt;dyn Feature&gt;) -&gt; Self;<br />⁠    async fn action(&amp;self) -&gt; Result&lt;String, String&gt;;<br />⁠  }<br />⁠<br />⁠  #[async_trait]<br />⁠  impl MyStructTrait for MyStruct {<br />⁠    fn new(feature: Arc&lt;dyn Feature&gt;) -&gt; Self {<br />⁠      MyStruct { feature }<br />⁠    }<br />⁠<br />⁠    async fn action(&amp;self) -&gt; Result&lt;String, String&gt; {<br />⁠      self.feature.action().await<br />⁠    }<br />⁠  }<br />⁠}</code></pre><figcaption>Using <mark>Arc</mark>, run in <a href="https://play.rust-lang.org/?version=stable&amp;mode=debug&amp;edition=2021&amp;gist=4ae4c1f16b5044c960d084775e347237" target="_blank"><strong>Rust Playground</strong></a>&nbsp;</figcaption><h2>Conclusion</h2><p>The <a href="https://www.lurklurk.org/effective-rust/generics.html" target="_blank">convenience of generics over trait objects</a> will depend on the context. Generics will have better performance, as its size is known at compile time and will use static dispatch; trait objects, on the other hand, will be send into the heap and will use dynamic dispatch, wich will have some memory overhead. But the flexibility it provides may worth it for many cases.</p><p>In short: each pointer —<mark>Box</mark>, <mark>Rc</mark> or <mark>Arc</mark>— will allow different actions:</p><ul><li><mark>Box</mark>: synchronous code where the trait object instance will be consumed once.</li><li><mark>Rc</mark>: synchronous code where the trait object instance will have to be cloned in order to feed different factories.</li><li><mark>Arc:</mark> asynchronous code that requires thread safety.</li></ul><p>With these four options —generics, <mark>Box</mark>, <mark>Rc</mark> and <mark>Arc</mark>— it is possible to perform dependency inversion and apply the patterns that may be required in our codebase. <br />⁠The full source code for the four examples can be found at <a href="https://www.git.antoniodiaz.me/antoniodcorrea/rust-dependency-inversion" target="_blank">&nbsp;<a href="https://www.git.antoniodiaz.me/antoniodcorrea/rust-dependency-inversion" target="_blank">git.antoniodiaz.me/antoniodcorrea/rust-dependency-inversion</a>&nbsp;</a>.</p></p>]]></description></item><item><title>Enum mapping in Rust and PostgreSQL </title><pubDate>Tue, 20 Jan 1970 00:00:00 GMT</pubDate><guid isPermaLink="true">https://www.antoniodiaz.me/en/blog/7</guid><description><![CDATA[<p><p>Some notes about type conversions between Rust and Postgres with <a href="https://docs.rs/tokio-postgres/latest/tokio_postgres/" target="_blank">tokio-postgres</a> library, async PostgreSQL client for Rust.  </p><p>There are two possibilities when mapping from Rust types into types related to some infrastructure:</p><ul><li>The type mapping from Postgres types into my Rust types.</li><li>The type mapping from Rust types into Postgres types.</li></ul><p>The library used, <a href="https://docs.rs/tokio-postgres/latest/tokio_postgres/" target="_blank">tokio-postgres</a> provides traits with some basic implementations that can be used to convert the application types into SQL types and the other way round. For example, there is <a href="https://docs.rs/postgres/latest/postgres/types/trait.FromSql.html" target="_blank">FromSQL</a>, which will automatically transform Rust primitives into PosgreSQL types: a Rust <mark>bool</mark> will be transformed into a Postgres <mark>bool</mark>; <mark>i64</mark> into <mark>bigint</mark>, <mark>&amp;str</mark> or <mark>String</mark> into <mark>text</mark>, and so on. It has to be done carefully, as some unintended results may arise if the developer is not sure about how types are converted; but in general it is consistent with the expectations.</p><p>The problem comes when it is required to perform type conversion between objects or some SQL types, as a postgres <mark>ENUM</mark> into a Rust <mark>enum</mark>. This is a common feature in libraries providing some kind of Object Relational Mapping (ORMs) functionality; thankfully <mark>tokio_postgres</mark> does not have this ability.</p><p>It is important to remark «thankfully»: ORMs are marketed as a way to speed up development for simple tasks; but they bring some issues into the projects, reason why they were called the <a href="http://web.archive.org/web/20061115004703/http://blogs.tedneward.com/2006/06/26/The+Vietnam+Of+Computer+Science.aspx" target="_blank">Vietnam of Computer Science</a>.</p><p>The debate about ORMs is long, and is filled with nuances; among others, there are two main points: </p><ul><li>ORMs force the developer to couple entity and infrastructure layers.</li><li>ORMs are unable to fill the gap between objects and relational structures except for basic cases. For any non trivial case, optimization performed by SQL is lost and queries are duplicated in order to build the required objects.</li></ul><p>Therefore, lacking an ORM and being required to manually map between Rust and Postgres types is not a drawback, but good practice. </p><h2>Mapping from SQL into Rust</h2><p>As previously mentioned, <mark>tokio-postgres</mark> exposes a <a href="https://docs.rs/postgres/latest/postgres/types/trait.FromSql.html" target="_blank">FromSQL</a> trait with a basic implementation for primitives and some specific types. With this implementation we don&#39;t have to worry about <mark>text</mark> conversion into <mark>String</mark>, or <mark>bigint</mark> into <mark>i64</mark>. </p><p>The issue arises when it is required a type conversion between a Postgres enum <mark>myenum</mark> into some Rust enum <mark>MyEnum</mark>.</p><pre><code>language-postgres<br />⁠<br />⁠create type myenum as enum(&#39;variant_a&#39;, &#39;variant_b&#39;);</code></pre><figcaption>Postgres type <mark>myenum</mark>&nbsp;</figcaption><pre><code>language-rust<br />⁠<br />⁠pub enum MyEnum {<br />⁠  VariantA,<br />⁠  VariantB,<br />⁠}</code></pre><figcaption>Rust type <mark>MyEnum</mark>&nbsp;</figcaption><p>Enum conversions are not supported by <a href="https://docs.rs/tokio-postgres/latest/tokio_postgres/" target="_blank">tokio-postgres</a>, as this library doesn&#39;t provide any <mark><u>Object &lt;-&gt; Relational</u></mark> mapping feature: the system won&#39;t know how to map one to the other. This is where the <a href="https://docs.rs/postgres/latest/postgres/types/trait.FromSql.html" target="_blank">FromSQL</a> trait exposed by the library can be handy to create an own implementation for the required Rust enum. </p><p><mark>FromSQL</mark> is a trait that exposes four methods, from which two will be useful for this case: <mark>from_sql</mark>, which will be in charge of actual type conversion, and <mark>accepts</mark>, which will check if the type conversion should be performed for the current type or not.</p><pre><code>language-rust<br />⁠<br />pub trait FromSql&lt;&#39;a&gt;: Sized {<br />⁠  fn from_sql(<br />⁠    ty: &amp;Type, <br />⁠    raw: &amp;&#39;a [u8]<br />⁠  ) -&gt; Result&lt;Self, Box&lt;dyn Error + Sync + Send&gt;&gt;;<br />⁠  […]<br />⁠  fn accepts(ty: &amp;Type) -&gt; bool;<br />⁠}</code></pre><figcaption><mark>FromSQL</mark> trait</figcaption><p>The task is actually easy:  <mark>from_sql</mark> will have to return the correct enum variants, which can be achieved matching against the raw binary string; in the <mark>accepts</mark> method is possible to perform a check against the name of the enum.</p><pre><code>language-rust<br />⁠<br />impl FromSql&lt;&#39;_&gt; for MyEnum {<br />⁠  fn from_sql(<br />⁠      _sql_type: &amp;Type, <br />⁠      value: &amp;[u8]<br />⁠    ) -&gt; Result&lt;Self, Box&lt;dyn Error + Sync + Send&gt;&gt; {<br />⁠    match value {<br />⁠      b&quot;variant_a&quot; =&gt; Ok(MyEnum::VariantA),<br />⁠      b&quot;variant_b&quot; =&gt; Ok(MyEnum::VariantB),<br />⁠      _ =&gt; Ok(MyEnum::VariantA),<br />⁠    }<br />⁠  }<br />⁠<br />⁠  fn accepts(sql_type: FromSqlType) -&gt; bool {<br />⁠    sql_type.name() == &quot;myenum&quot;<br />⁠  }<br />⁠}</code></pre><figcaption>Mapping from <mark>myenum</mark> Postgres type into <mark>MyEnum</mark> Rust type</figcaption><p>As this implementation is related to Postgres, it can live within the Postgres repository or the database related code, and outside of the entities and domain layer. This way it is avoided coupling domain and infrastructure, being infrastructure who is referencing the domain —when mentioning <mark>MyEnum</mark>—, and not the other way round.</p><p>This implementation will tell&nbsp;<a href="https://docs.rs/tokio-postgres/latest/tokio_postgres/" target="_blank">tokio-postgres</a> how to perform type conversion between SQL and Rust for this specific type, so everytime a query returns a <mark>myenum</mark> Postgres type, it will appear in the application as <mark>MyEnum</mark>.</p><h2>Mapping from Rust into SQL</h2><p>The opposite case is when in the database there is a <mark>myenum</mark> Postgres type that should be exposed to our application. <a href="https://docs.rs/tokio-postgres/latest/tokio_postgres/" target="_blank">tokio-postgres</a> can perform this type conversion, but this will require a custom implementation of <a href="https://docs.rs/postgres/latest/postgres/types/trait.ToSql.html" target="_blank">ToSql</a> trait using <mark>to_sql</mark> and <mark>accepts</mark> methods:</p><pre><code>language-rust<br />⁠<br />pub trait ToSql: fmt::Debug {<br />⁠    fn to_sql(<br />      &amp;self, <br />⁠      ty: &amp;Type, <br />⁠      out: &amp;mut BytesMut<br />⁠    ) -&gt; Result&lt;IsNull, Box&lt;dyn Error + Sync + Send&gt;&gt; where Self: Sized;<br />⁠<br />⁠    fn accepts(ty: &amp;Type) -&gt; bool where Self: Sized;<br />⁠<br />⁠    fn to_sql_checked(<br />⁠      &amp;self,<br />⁠      ty: &amp;Type,<br />⁠      out: &amp;mut BytesMut,<br />⁠    ) -&gt; Result&lt;IsNull, Box&lt;dyn Error + Sync + Send&gt;&gt;;<br />⁠}</code></pre><figcaption><mark>ToSQL</mark> trait</figcaption><p>It is required to implement <mark>to_sql_checked</mark> as well, but the <mark>types::to_sql_checked!</mark>&nbsp;<a href="https://docs.rs/postgres/latest/postgres/types/macro.to_sql_checked.html" target="_blank">macro</a> can generate this method implementation  automatically.</p><p>When implementing <mark>to_sql</mark> the <mark>Rust</mark> enum variant should be transformed into a <mark>&amp;str</mark> first, which can be achieved implementing <mark>Display</mark> for <mark>MyEnum</mark> in order to map between <mark>MyEnum</mark> variants and a string.</p><pre><code>language-rust<br />⁠<br />use std::fmt::{Display, Formatter, Result };<br />⁠<br />⁠impl Display for MyEnum {<br />⁠  fn fmt(&amp;self, f: &amp;mut Formatter) -&gt; Result {<br />⁠    match self {<br />⁠      MyEnum::VariantA =&gt; write!(f, &quot;variant_a&quot;),<br />⁠      MyEnum::VariantB =&gt; write!(f, &quot;variant_b&quot;),<br />    }<br />⁠  }<br />⁠}</code></pre><figcaption>Implementing <mark>Display</mark> for <mark>MyEnum</mark></figcaption><p>After implementing <mark>Display</mark> for <mark>MyEnum</mark> it is possible to implement <mark>ToSql</mark> for <mark>MyEnum</mark>:</p><pre><code>language-rust<br />⁠<br />use tokio_postgres::{<br />⁠  types::{to_sql_checked, ToSql, IsNull, Type},<br />⁠};<br />⁠use bytes::BytesMut;<br />⁠use std::{error::Error, result::Result};<br />⁠<br />⁠impl ToSql for Role {<br />⁠  fn to_sql(<br />⁠    &amp;self, <br />⁠    ty: &amp;Type, <br />⁠    out: &amp;mut BytesMut<br />⁠  ) -&gt; Result&lt;IsNull, Box&lt;dyn Error + Sync + Send&gt;&gt;; {<br />⁠    format!(&quot;{}&quot;, self).to_sql(ty, out)<br />⁠  }<br />⁠<br />⁠  fn accepts(sql_type: &amp;Type) -&gt; bool {<br />⁠    sql_type.name() == &quot;myenum&quot;<br />⁠  }<br />⁠<br />⁠  to_sql_checked!();<br />⁠}</code></pre><figcaption>Implementing ToSql for <mark>MyEnum</mark></figcaption><p>⁠With this, every time Postgres receives a Rust <mark>MyEnum</mark>, it will be converted into Postgres <mark>myenum</mark>.</p><h2>Conclusion</h2><p>There are other cases where we will need to perform some type conversion, as with the <mark>Row</mark> type that can be used with Rust&#39;s trait <mark>From</mark> to convert between Postgres rows into Rust entity objects. For example, for a given struct <mark>Article</mark>, the <mark>From</mark> implementation on the repository may look like this:</p><pre><code>language-rust<br />⁠<br />// Domain<br />⁠pub struct Article {<br />⁠  pub id: String,<br />⁠  pub title: String,<br />⁠  pub created_at: DateTime,<br />⁠}<br />⁠<br />⁠// Repository<br />⁠impl From&lt;Row&gt; for Article {<br />⁠  fn from(row: Row) -&gt; Self {<br />⁠    Self {<br />⁠      id: row.get(&quot;id&quot;),<br />⁠      title: row.get(&quot;title&quot;),<br />⁠      created_at: row.get(&quot;created_at&quot;),<br />⁠    }<br />⁠  }<br />⁠}<br /><br />⁠let result = client.query(&quot;select * from article&quot;).await?;<br />⁠let articles: Vec&lt;Article&gt; = result.into_iter()<br />⁠    .map(Article::from)<br />    ⁠.collect();</code></pre><figcaption>Implementing <mark>From&lt;Row&gt;</mark> for some object <mark>Article</mark></figcaption><p>In general this library it is quite straightforward to use, and limits its own features allowing us to manually perform our type conversion.</p></p>]]></description></item></channel></rss>