<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[StackAnatomy - Medium]]></title>
        <description><![CDATA[Quality content for front-end developers - Medium]]></description>
        <link>https://medium.com/stackanatomy?source=rss----48c8bfd9e724---4</link>
        <image>
            <url>https://cdn-images-1.medium.com/proxy/1*TGH72Nnw24QL3iV9IOm4VA.png</url>
            <title>StackAnatomy - Medium</title>
            <link>https://medium.com/stackanatomy?source=rss----48c8bfd9e724---4</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Thu, 12 Nov 2026 23:08:20 GMT</lastBuildDate>
        <atom:link href="https://medium.com/feed/stackanatomy" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Forever Functional #39 — Workers and Promises]]></title>
            <link>https://medium.com/stackanatomy/forever-functional-39-workers-and-promises-66839ea34c70?source=rss----48c8bfd9e724---4</link>
            <guid isPermaLink="false">https://medium.com/p/66839ea34c70</guid>
            <category><![CDATA[functional-programming]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[javascript-development]]></category>
            <category><![CDATA[asynchronous-programming]]></category>
            <category><![CDATA[promises]]></category>
            <dc:creator><![CDATA[Federico Kereki]]></dc:creator>
            <pubDate>Sun, 01 Sep 2024 12:43:28 GMT</pubDate>
            <atom:updated>2025-06-28T23:11:20.353Z</atom:updated>
            <content:encoded><![CDATA[<h3>Forever Functional #39 — Workers and Promises</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*peAjHF7X8A4alRrI.png" /></figure><p><em>JavaScript provides concurrency when using async functions; even if a single processor does all the work, several tasks may be ongoing simultaneously. To get better performance, you may use </em><a href="https://developer.mozilla.org/en-US/docs/Web/API/Worker"><em>web workers</em></a><em> (at the front end, in a browser) and </em><a href="https://nodejs.org/api/worker_threads.html"><em>worker threads</em></a><em> (at the back end). This article will show you how to work with workers in a functional, efficient way.</em></p><p>The basic mechanism for using workers is messaging, but that has some limitations-plus, it really isn’t very functional!- so let’s see how we may use workers in a functional way to optimize the performance of our code.</p><h3>A sample worker</h3><p>In a <a href="https://blog.openreplay.com/forever-functional-memoizing-functions-for-performance/">previous article</a>, we saw that a naïve straightforward implementation of the Fibonacci numbers could have serious time performance issues. Let’s use that as a worker, so we’ll have something to do that might take a long time, depending on whatever argument we pass to it.</p><pre>// File: ./workers/sample_fib_worker.mjs<br><br>import { parentPort } from &#39;worker_threads&#39;;<br><br>const fibonacci = (i) =&gt; (i &lt; 2 ? i : fibonacci(i - 1) + fibonacci(i - 2));<br><br>function fakeWorker(n) {<br>  const result = fibonacci(n);<br>  parentPort.postMessage(`fib(${n})=${result}`);<br>}<br><br>parentPort.on(&#39;message&#39;, fakeWorker);</pre><p>The <a href="https://nodejs.org/api/worker_threads.html#workerparentport">parentPort</a> attribute is how the worker communicates with the parent. Then, we have the definition of the i-th Fibonacci number and how we&#39;ll use it. Finally, the last line defines, by using the onmessage method, what the worker should do with the argument it receives. The received value will be passed to the fakeWorker function, which will use the postMessage method to return the calculation&#39;s result; in this case, something like fib(7)=13.</p><h3>Using workers through messages</h3><p>Suppose we wanted to perform the Fibonacci calculations in a thread to avoid blocking Node’s event loop (at the back end) or seemingly showing a dead, non-responding screen (at the front end). The simplest way of doing this is as follows; we’ll use Node.js for simplicity, but code would be similar at a browser.</p><pre>import { Worker } from &#39;worker_threads&#39;;<br>const worker = new Worker(&#39;./workers/sample_fib_worker.mjs&#39;);<br><br>worker.postMessage(40);<br>worker.postMessage(35);<br>worker.postMessage(45);<br>worker.postMessage(15);<br><br>worker.on(&#39;message&#39;, console.log);<br><br>process.stdin.resume();       // keep Node running<br>process.on(&#39;SIGINT&#39;, () =&gt; {  // on Control+C, end<br>  worker.terminate();<br>  process.exit();<br>});</pre><p>First, we create a worker based on the code we saw in the previous section. We send several messages (using the postMessage method), and the four requests will be queued and processed in the order they are received. The last lines are just to keep Node running (otherwise, the program would end before the worker had a chance to do its job) and to clean up (by terminating the worker) on Control+C.</p><p>The output is the following.</p><pre>fib(40)=102334155<br>fib(35)=9227465<br>fib(45)=1134903170<br>fib(15)=610</pre><p>This works well, but if you wanted to call the same worker several times in parallel, that would require creating separate workers and handling messages in different ways. (As is, the four calls in our example are processed serially.) Also, message passing doesn’t look very functional, so let’s try using promises.</p><h3>Using workers through promises</h3><p>We can create a promise out of a worker and have it resolved when the worker sends its result.</p><pre>import { Worker } from &#39;worker_threads&#39;;<br><br>const callWorker = (filename, value) =&gt;<br>  new Promise((resolve, reject) =&gt; {<br>    const worker = new Worker(filename);<br>    worker.on(&#39;message&#39;, (value) =&gt; {<br>      resolve(value);<br>      worker.terminate();<br>    });<br>    worker.on(&#39;error&#39;, (err) =&gt; {<br>      reject(err);<br>      worker.terminate();<br>    });<br>    worker.postMessage(value);<br>  });</pre><p>The callWorker function builds a promise, given the worker to create and the value to pass to it. If the worker succeeds, the resolve function is used to fulfill the promise; on an error, reject is called instead. In both cases, we terminate the worker because it&#39;s done.</p><p>Now, we can run several workers in parallel.</p><pre>callWorker(&#39;./workers/sample_fib_worker.mjs&#39;, 40).then(console.log);<br>callWorker(&#39;./workers/sample_fib_worker.mjs&#39;, 35).then(console.log);<br>callWorker(&#39;./workers/sample_fib_worker.mjs&#39;, 45).then(console.log);<br>callWorker(&#39;./workers/sample_fib_worker.mjs&#39;, 15).then(console.log);</pre><p>We are creating four promises that will run in parallel. We are just logging their results here, but we could obviously do other things. The output will be in different order because the four calls do not take the same time to complete.</p><pre>fib(15)=610<br>fib(35)=9227465<br>fib(40)=102334155<br>fib(45)=1134903170</pre><p>This is very good and enables us to parcel out work to threads and work in parallel as well. However, there’s an issue; every time you use callWorker, a new worker has to be created (so code must be read and parsed again), which will cause delays. What can we do?</p><h3>Using workers with a pool</h3><p>As we saw earlier, workers can stay unterminated, and as they receive new messages, they can reply to them. This suggests a solution: keep the workers in a pool, do not terminate them, and reuse them if possible. When we want to call a worker, we first check the pool to see if there’s already an appropriate available (meaning, not in use) worker. If we find it, we can directly call it, but if not, we create a new one.</p><p>The pool entries will have three attributes:</p><ul><li>worker, the worker itself</li><li>filename, which was used to create the worker</li><li>available, which is set to false when the worker is running, and to true when it&#39;s done and ready to do a new calculation</li></ul><p>The callWorker method now becomes:</p><pre>// file: ./workers/pool.mjs<br><br>import { Worker } from &#39;worker_threads&#39;;<br><br>const pool = [];<br><br>export const callWorker = (filename, value) =&gt; {<br>  let available = pool<br>    .filter((v) =&gt; !v.inUse)<br>    .find((x) =&gt; x.filename === filename);<br>    <br>  if (available === undefined) {<br>    available = {<br>      worker: new Worker(filename),<br>      filename,<br>      inUse: true<br>    };<br>    pool.push(available);<br>  }<br><br>  return new Promise((resolve, reject) =&gt; {<br>    available.inUse = true;<br>    available.worker.on(&#39;message&#39;, (x) =&gt; {<br>      resolve(x);<br>      available.inUse = false;<br>    });<br>    available.worker.on(&#39;error&#39;, (x) =&gt; {<br>      reject(x);<br>      available.inUse = false;<br>    });<br>    available.worker.postMessage(value);<br>  });<br>};</pre><p>The callWorker code has two parts. Initially, it searches the pool for an available worker ( inUse should be false) with the correct filename. If the search fails, a new worker is added to the pool. After that, the logic is similar to what we saw in the previous section; the main difference is that we must update the inUse attribute appropriately.</p><p>Using this pool works the same way as earlier, but the difference is that it won’t create unnecessary workers if it can reuse previous ones. We still use promises and have parallel processing, but we now add a bit more efficiency; a win!</p><h3>Conclusion</h3><p>Using workers provides several benefits, like processing in different threads, which isn’t as common in JavaScript as in other languages such as Java or Rust. Using workers through promises enables a more functional working style, and the final addition of a pool gives extra performance; several wins for us!</p><p><em>If you want to read about programming (including functional programming, of course), algorithms in general, and data structures and their applications, take a look at my </em><a href="https://www.amazon.com/Structures-Algorithms-JavaScript-Federico-Kereki/dp/1718502621/ref=sr_1_3"><em>DATA STRUCTURES AND ALGORITHMS IN JAVASCRIPT</em></a><em> and </em><a href="https://www.amazon.com/Mastering-JavaScript-Functional-Programming-maintainable/dp/1804610135/ref=sr_1_5"><em>MASTERING JAVASCRIPT FUNCTIONAL PROGRAMMING</em></a><em> books.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/779/1*NOWSsSbVG71zNQb5QXbn8Q.png" /></figure><p><em>Originally published at </em><a href="https://blog.openreplay.com/forever-functional-workers-and-promises-together/"><em>https://blog.openreplay.com</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=66839ea34c70" width="1" height="1" alt=""><hr><p><a href="https://medium.com/stackanatomy/forever-functional-39-workers-and-promises-66839ea34c70">Forever Functional #39 — Workers and Promises</a> was originally published in <a href="https://medium.com/stackanatomy">StackAnatomy</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Forever Functional #38 — Of maps and pipes, chains and nests, and more]]></title>
            <link>https://medium.com/stackanatomy/forever-functional-38-of-maps-and-pipes-chains-and-nests-and-more-ad6a473ee724?source=rss----48c8bfd9e724---4</link>
            <guid isPermaLink="false">https://medium.com/p/ad6a473ee724</guid>
            <category><![CDATA[functional-programming]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[typescript]]></category>
            <category><![CDATA[algorithms]]></category>
            <dc:creator><![CDATA[Federico Kereki]]></dc:creator>
            <pubDate>Sun, 01 Sep 2024 12:43:25 GMT</pubDate>
            <atom:updated>2025-11-16T17:21:38.119Z</atom:updated>
            <content:encoded><![CDATA[<h3>Forever Functional #38 — Of maps and pipes, chains and nests, and more</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*be_6JEbGrxasQJId.png" /></figure><p><em>Can we combine functions by using mapping? What about this in relation to function composition and pipelining? And what does it have to do with chaining and nesting? This article will reply to all those questions, showing you how to join functions together for clearer, more expressive code.</em></p><p>The array <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map">.map(...)</a> method is very powerful and lets us write more understandable code. Let&#39;s ask a theoretical question and see where it takes us. Could we apply map() to other types and not only to arrays? Why not?</p><p>In this article we’ll start by extending types to allow mapping, and then get into pipelines, chaining, nesting, and several other functional programming concepts; just wait!</p><h3>Mapping for other types</h3><p>First, we could add it to basic types, such as booleans, numbers, bigInts, and strings. On the other hand, it seems that adding mapping to null, undefined, and symbol wouldn&#39;t be that great, so we&#39;d skip that. And, obviously, adding a map() method to objects (or to class definitions) is straightforward; no mystery there.</p><p>In all cases code would be something like this — we’ll only show two definitions to avoid repetition:</p><pre>Boolean.prototype.map = <br>  function(fn) { <br>    return Boolean(fn(this));<br>  };<br><br>Number.prototype.map = <br>  function(fn) {<br>    return Number(fn(this));<br>  };</pre><p>We can now write things like the following two examples, and let’s use <a href="https://medium.com/stackanatomy/forever-functional-pointfree-style-programming-c3877c229ceb">pointfree style</a> for a more “functional-programming-ish” style:</p><pre>const not = (x) =&gt; -x;<br>let someFlag = true;<br>someFlag.map(not); // false<br><br>const negate = (z) =&gt; -z;<br>let aNumber = 22;<br>aNumber.map(negate); // -22</pre><p>This isn’t a real win; we could have written not(someFlag) and negate(aNumber) equally well. There&#39;s a slim advantage: we can now clearly chain sequences of operations. Let&#39;s go with a simple example.</p><pre>const add1 = z =&gt; z+1;<br>const times10 = z =&gt; 10 * z;<br><br>aNumber.map(add1).map(times10).map(negate); // -230</pre><p>This starts to look more interesting; the alternative way, negate(times10(add1(aNumber))) wouldn&#39;t have been equally clear. We&#39;ll look into this a bit more, but first, we must answer the question: what about using map() with functions?</p><h3>Mapping functions</h3><p>Functions are (trivially!) essential, and we should investigate what mapping would mean for them. The logical definition would be as follows; if we have f1 and f2 functions and we write f1.map(f2), that should return a function that first runs f1 and then applies f2 to whatever f1 returned.</p><pre>Function.prototype.map = function (fn) {<br>  return (x) =&gt; fn(this(x));<br>};<br><br>add1.map(times10)(3); // 40</pre><p>So, x =&gt; f1.map(f2)(x) is equivalent to x =&gt; f2(f1(x)), and in general x =&gt; f1.map(f2).map(f3)...map(fn)(x) would be the same as x =&gt; fn(...f3(f2(f1(x)))). This is a well-known functional programming concept that we should look into!</p><h3>Maps as composition?</h3><p>The kind of expression we wrote in the previous paragraph, when you have a sequence of functions call in which the output of one function is the input of the next one, is called <em>composition</em>. Formally, in mathematical terms, instead of fn(...f3(f2(f1(x)))) you could also write (fn∘...∘f3∘f2∘f1)(x). If you wish, you can read ∘ as <em>after</em>, so f2∘f1 is f2 after f1, etc.</p><p>If we wish, we can write a general compose(...) function; it&#39;s not hard - can you see why and how the code below works?</p><pre>function compose(...fns) {<br>  return fns.reduceRight(<br>    (f, g) =&gt;<br>      (...args) =&gt;<br>        g(f(...args)),<br>  );<br>}</pre><p>So, instead of writing x =&gt; f1.map(f2).map(f3)(x) you could go with x =&gt; compose(f3, f2, f1)(x) - but that goes a bit against the grain; the order of functions is reversed! There&#39;s another concept we should look into: pipelining!</p><h3>Maps as pipes</h3><p>In Unix and Linux, the idea of running a first command, passing its output as input to a second command, whose output will be input for yet a third command, etc., is called a <em>pipeline</em>. This is a basic philosophy of Unix, and Doug McIlroy, the creator of the pipelining concept, explained:</p><ul><li>Make each program do one thing well. To do a new job, build afresh rather than complicate old programs by adding new features.</li><li>Expect the output of every program to become the input to another, so far unknown program.</li></ul><p>To give an elementary example (from my <a href="https://www.amazon.com/Mastering-JavaScript-Functional-Programming-maintainable/dp/1804610135">Mastering JavaScript Functional Programming</a> book) if you wanted to count how many LibreOffice text documents there are in a directory, the following pipeline would do:</p><pre>ls -1 | grep &quot;odt$&quot; | wc -l</pre><p>How does this work?</p><ul><li>The first command lists all the files in a single column, one filename per line.</li><li>The second command gets the list of files and filters (let pass) only those that end with “odt”, the standard file extension for LibreOffice Writer documents.</li><li>The third command gets the filtered list and counts how many lines there are in it.</li></ul><p>It seems then that something like f1.map(f2).map(f3) is like a Unix pipeline, sort of f1 | f2 | f3 thing. It so happens that there is <a href="https://github.com/tc39/proposal-pipeline-operator">a proposal</a> to include such an operator in JavaScript, written |&gt; as in f1 |&gt; f2 |&gt; f3, but it isn&#39;t accepted yet.</p><p>Given that pipelining is just like composition but working “the other way”, we can quickly whip up the following:</p><pre>function pipeline(...fns) {<br>  return fns.reduce(<br>    (result, f) =&gt;<br>      (...args) =&gt;<br>        f(result(...args)),<br>  );<br>}</pre><p>In that case, we could write any of the following versions — though the last two won’t work until the pipeline operator proposal is accepted:</p><pre>aNumber.map(add1).map(times10).map(negate);<br>aNumber.map(add1.map(times10).map(negate));<br><br>pipeline(add1, times10, negate)(aNumber);<br>aNumber.map(pipeline(add1, times10, negate));<br><br>(add1 |&gt; times10 |&gt; negate)(aNumber); <br>aNumber.map(add1 |&gt; times10 |&gt; negate);</pre><p>What do you think? Personally, I believe that this “ <em>chaining style</em>” for successive functions is clearer than the alternative “ <em>nesting style</em>” (based on composing) which adds the extra complexity of listing the functions in reverse order. The piping way, the <a href="https://en.wikipedia.org/wiki/Fluent_interface">fluent interface pattern</a>, is more understandable, and adding our map/pipe method allows us to easily use it.</p><h3>Conclusion</h3><p>We started this article by wondering about extending the usage of map() to other data types, went from there to using it on functions, and ended up considering typical functional programming topics such as composition and pipelining. JavaScript can be considered a multi-paradigm language, and the examples we&#39;ve seen here confirm that... and also allow you greater freedom to achieve the maximum clarity in your code!</p><p><em>If you want to read about programming (including functional programming, of course), algorithms in general, and data structures and their applications, take a look at my </em><a href="https://www.amazon.com/Structures-Algorithms-JavaScript-Federico-Kereki/dp/1718502621/ref=sr_1_3"><em>DATA STRUCTURES AND ALGORITHMS IN JAVASCRIPT</em></a><em> and </em><a href="https://www.amazon.com/Mastering-JavaScript-Functional-Programming-maintainable/dp/1804610135/ref=sr_1_5"><em>MASTERING JAVASCRIPT FUNCTIONAL PROGRAMMING</em></a><em> books.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/779/1*NOWSsSbVG71zNQb5QXbn8Q.png" /></figure><p><em>Originally published at </em><a href="https://blog.openreplay.com/forever-functional-of-maps-pipes-chains-and-more/"><em>https://blog.openreplay.com</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ad6a473ee724" width="1" height="1" alt=""><hr><p><a href="https://medium.com/stackanatomy/forever-functional-38-of-maps-and-pipes-chains-and-nests-and-more-ad6a473ee724">Forever Functional #38 — Of maps and pipes, chains and nests, and more</a> was originally published in <a href="https://medium.com/stackanatomy">StackAnatomy</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Forever Functional #40 — Better Error Handling with Monads (Part 1)]]></title>
            <link>https://medium.com/stackanatomy/better-error-handling-with-monads-part-1-970076a1d1f4?source=rss----48c8bfd9e724---4</link>
            <guid isPermaLink="false">https://medium.com/p/970076a1d1f4</guid>
            <category><![CDATA[monads]]></category>
            <category><![CDATA[error-handling]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[functional-programming]]></category>
            <dc:creator><![CDATA[Federico Kereki]]></dc:creator>
            <pubDate>Sun, 01 Sep 2024 12:42:27 GMT</pubDate>
            <atom:updated>2026-03-07T15:47:09.468Z</atom:updated>
            <content:encoded><![CDATA[<h3>Forever Functional #40 — Better Error Handling with Monads (Part 1)</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*9otl6v2cj9bytl68.png" /></figure><p><em>What are monads? How do you create them in JavaScript, and how do you use them? What problems do they solve? Why should one care about monads and add them as a tool for development? This article will start with basic requirements to show what monads are and how to create them, and </em><a href="https://fkereki.medium.com/better-error-handling-with-monads-part-2-ca05e20e3a14"><em>in the second part</em></a><em> we’ll see how and when to use them, simplifying error handling everywhere.</em></p><p>Using <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map">the </a><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map">.map() method</a> allows for shorter, clearer, declarative-style programming, so we would want to be able to use it more. In a <a href="https://fkereki.medium.com/forever-functional-38-of-maps-and-pipes-chains-and-nests-and-more-ad6a473ee724">previous article</a>, we saw that we could extend individual types to allow adding this method to them. However, that is sort of limited and requires repeating the definition for each type. So, we&#39;ll work in a different, more general way and eventually get to <em>monads</em>, which are way more powerful than just &quot;types with maps&quot;!</p><ol><li>We’ll start by defining <em>containers</em>, which work with any type</li><li>We’ll then add some features and get more power with <em>functors</em></li><li>We’ll finish by adding some more capabilities and producing <em>monads</em></li></ol><p>We could do this using classes, but we’ll go with vanilla JavaScript, which is as basic and compatible as possible. We’ll be using <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/Object">object constructors</a> instead of classes, and <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures">closures</a> instead of attributes, as you’ll see.</p><blockquote>The curse of the monad is that once you get the epiphany, once you understand-”oh that’s what it is”-you lose the ability to explain it to anybody. <a href="https://www.youtube.com/watch?v=dkZFtimgAcM">Douglas Crockford</a></blockquote><h3>First Step: Defining Containers for all data types</h3><p>We want something that will contain a value of any type and (at the very least) allow us to apply a .map() method to it. The following code does just that:</p><pre>function Container(x) {<br>  this.map = (fn) =&gt; fn(x);     // ➊<br>  this.toString =               // ➋<br>    () =&gt; `${this.constructor.name}(${x})`; <br>  this.valueOf = () =&gt; x;       // ➌<br>}</pre><p>Let’s study the code. The method we care about is .map(); given a fn function, it applies it to the container&#39;s value x ➊.</p><blockquote>Note: The x value is not stored as an attribute but rather accessed through a closure, making the value inaccessible from the outside.</blockquote><p>We added a couple more methods. The <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString">standard </a><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString">.toString() method</a> is overridden to get a more accurate description of the container and its value ➋. Finally ➌, the .valueOf() method is just a help for debugging, because you could easily write someContainer.map(console.log) and see the container&#39;s value.</p><p>How do we use these containers? We can create a container with a value of any type; an example follows.</p><pre>const plus1 = (x) =&gt; x+1;      // ➊<br>const ccc = new Container(22); // ➋<br>ccc.map(plus1);                // ➌ 23<br>ccc.valueOf();                 // ➍ 22<br>ccc.toString();                // ➎ Container(22)</pre><p>First ➊ we define an auxiliary plus1() function that we&#39;ll use in our tests. Then ➋ we create a container for a numeric value, 22. The following line (written in <a href="https://medium.com/stackanatomy/forever-functional-pointfree-style-programming-c3877c229ceb">pointfree style</a>) shows how to use .map() ➌ with the same notation used for arrays. Finally, the last lines ➍ ➎ illustrate our additional methods; we see that the original ccc container wasn&#39;t modified and still has the 22 value inside.</p><p>OK, these containers work, but they are roughly equivalent to variables. We wanted to be able to use .map(), and we managed that, but we cannot chain operations as we did in our <a href="https://medium.com/stackanatomy/forever-functional-chaining-calls-for-fluent-interfaces-a88996c3bc3c">previous article on fluent interfaces</a>, so we must work a bit more, and go from containers to <em>functors</em>.</p><h3>Second Step: Adding more power by using Functors</h3><p>Containers are good, but we need .map() to return a container so we can chain more operations. By changing the definition of the operation, we have moved to a new kind of object, a <em>functor</em>.</p><p>Essentially, a functor is just a container (as we’ve created it), but we need its .map() operation to return a new functor, not just a value. This is precisely what happens with arrays: when you use .map(), you produce a new array, so now we realize that arrays are functors! The needed change is small.</p><pre>function Functor(x) {<br>  Container.call(this, x);             // ➊<br>  this.map = (fn) =&gt; <br>    new this.constructor(fn(x));       // ➋<br>}</pre><p>We start ➊ by invoking the Container constructor, so our functors will share their three methods. The following line ➋ overrides the inherited .map() method with a new implementation that returns a new functor, allowing us to chain operations as in the example below.</p><pre>const plus1 = (x) =&gt; x+1;<br>const ccc = new Functor(22);           // ➊<br>const ddd = ccc.map(plus1).map(plus1); // ➋<br>ddd.map(plus1).valueOf();              // ➌ 25<br>ddd.toString();                        // ➍ Functor(24);</pre><p>This example is like the one for containers, but instead of creating a container ➊ we built a functor. This allows us ➋ ➌ to chain several operations. The last line ➍ shows that ddd is a functor containing 24.</p><p>These functors are better suited for coding than our plain containers, but there still are a couple of kinks we must work out; let’s go on to <em>monads</em>!</p><h3>Third (and last) Step: Get maximum flexibility by using Monads</h3><p>There’s a problem we still need to consider… Let’s assume a fun functor and a makeFun(...) function that returns a functor. What would fun.map(makeFun) produce? The answer: we&#39;d get a functor whose value would be a second functor! This would make coding very difficult; to apply a function to the value in the second functor you would have to write code such as fun.map(makeFun).map((x) =&gt; x.map((y) =&gt; someOtherFunction(y))); neither practical nor clear!</p><p>We will extend functors to create a new type, <em>monads</em>. We want monads to be able to “unwrap” the value a function returns (if needed) so we won’t get values wrapped two or more times. We will have a new unwrap() (internal) function, and a .chain() method that will use it to unwrap possibly wrapped values.</p><pre>function Monad(x) {<br>  Functor.call(this, x);                 // ➊<br>  const unwrap = (z) =&gt; z.chain ? <br>    unwrap(z.valueOf()) : z;             // ➋<br>  this.chain = (fn) =&gt; <br>    new this.constructor(unwrap(fn(x))); // ➌<br>}</pre><p>Monads are functors, so we start ➊ by calling the corresponding constructor. Our unwrap() function ➋ detects if its argument is a monad by seeing if it has a .chain() method; other ways of doing this detection could be used. The .chain() method ➌ is precisely like .map(), but it takes care of unwrapping whatever is returned by fn(x), so the resulting monad won&#39;t be wrapping anything more than once.</p><p>Working with monads is, so far, exactly the same as with functors. The only difference is that you would probably prefer using .chain() to avoid double wrapping for values, but in most cases, .map() will do.</p><h3>Functions in monads</h3><p>So far, we have been storing “common” values in monads, like numbers. But, as with variables, we could think of storing a <em>function</em> in a monad, like in the example below. Would that work? Of course, it should, but how would we use the contained function?</p><pre>const nnn = new Monad(22);      // ➊<br>const add = (x) =&gt; (y) =&gt; x+y;  // ➋<br>const fun = nnn.map(add);       // ➌</pre><p>We first create a monad ➊ containing a number. The add() function, written <a href="https://medium.com/stackanatomy/forever-functional-16-many-flavors-of-currying-e87d6ee198ac">in curried style</a> as usual in functional programming. When we apply add() to the monad ➌ we get a new monad whose value is a function that will add 22 to whatever it&#39;s applied to. But how will we be able to do that? We could write something awkward like the following, using two .map() operations, but that&#39;s not clear or practical!</p><pre>const ooo = new Monad(9);<br>const ppp = ooo.map((x) =&gt; fun.map((f) =&gt; f(x)));</pre><p>Instead of that roundabout way of working, we’ll define a new .ap() method that will allow us to apply a function in a monad to any value that allows mapping.</p><pre>function Monad(x) { <br>  // ...all the previous code, plus:<br>  this.ap = (v) =&gt; v.map(x); // ➊<br>}<br><br>fun.ap(ooo);                 // ➋ Monad(31)</pre><p>We need just one line ➊ to define the new .ap() method, which will apply the contained function to a given value v by mapping. We can see this working ➋ more clearly; we can now apply the function in the fun monad to another monad ( ooo) without complications.</p><blockquote>Note: you could want to write something like fun.ap(9), but that wouldn&#39;t work because plain numbers don&#39;t provide a .map() method. Can you fix this so .ap() will also work with numbers, strings, booleans, etc.? We&#39;ll leave this up to you as an exercise!</blockquote><h3>Conclusion</h3><p>We have now reached our first goal; we implemented monads! We started with basic containers, made a small change to get functors, and added more power to get monads. We did all of this using vanilla JS, starting from basic requirements.</p><p>However, just showing how monads are defined is interesting, but the real deal is seeing why and how they simplify coding, dealing with errors, working with missing values, and more — we’ll get to that in <a href="https://fkereki.medium.com/better-error-handling-with-monads-part-2-ca05e20e3a14">part 2 of this article</a>; stay tuned!</p><p><em>If you want to read about programming (including functional programming, of course), algorithms in general, and data structures and their applications, take a look at my </em><a href="https://www.amazon.com/Structures-Algorithms-JavaScript-Federico-Kereki/dp/1718502621/ref=sr_1_3"><em>DATA STRUCTURES AND ALGORITHMS IN JAVASCRIPT</em></a><em> and </em><a href="https://www.amazon.com/Mastering-JavaScript-Functional-Programming-maintainable/dp/1804610135/ref=sr_1_5"><em>MASTERING JAVASCRIPT FUNCTIONAL PROGRAMMING</em></a><em> books.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/779/1*NOWSsSbVG71zNQb5QXbn8Q.png" /></figure><p><em>Originally published at </em><a href="https://blog.openreplay.com/forever-functional-better-error-handling-with-monads--part-1/"><em>https://blog.openreplay.com</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=970076a1d1f4" width="1" height="1" alt=""><hr><p><a href="https://medium.com/stackanatomy/better-error-handling-with-monads-part-1-970076a1d1f4">Forever Functional #40 — Better Error Handling with Monads (Part 1)</a> was originally published in <a href="https://medium.com/stackanatomy">StackAnatomy</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Forever Functional #41 —  Better Error Handling with Monads (Part 2)]]></title>
            <link>https://medium.com/stackanatomy/better-error-handling-with-monads-part-2-ca05e20e3a14?source=rss----48c8bfd9e724---4</link>
            <guid isPermaLink="false">https://medium.com/p/ca05e20e3a14</guid>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[monads]]></category>
            <category><![CDATA[error-handling]]></category>
            <category><![CDATA[functional-programming]]></category>
            <dc:creator><![CDATA[Federico Kereki]]></dc:creator>
            <pubDate>Sun, 01 Sep 2024 12:42:22 GMT</pubDate>
            <atom:updated>2026-03-07T15:47:20.327Z</atom:updated>
            <content:encoded><![CDATA[<h3>Forever Functional #41 — Better Error Handling with Monads (Part 2)</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*RxZSAYdiaDUinelV.png" /></figure><p><a href="https://fkereki.medium.com/better-error-handling-with-monads-part-1-970076a1d1f4"><em>The first part of this article</em></a><em> explained monads and wrote vanilla JS code for them. Now, this second part answers the big question: What are monads good for, and why should you use them?</em></p><p>Monads have several uses, so let’s start by showing how to deal with “the billion dollar mistake”, mishandling null values, in a very simple way.</p><h3>Null values: “The Billion Dollar Mistake”</h3><p>Anthony Hoare, the inventor of <a href="https://en.wikipedia.org/wiki/Quicksort">Quicksort</a>, spoke <a href="https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare/">a few years ago</a> about his “invention” of null references:</p><blockquote>I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object-oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn’t resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.</blockquote><p>Given the unending list of bugs that have occurred because of null pointers, missing values, undefined results, and the like, it seems that any solution that helps deal more carefully with this kind of situation would be welcome! It happens that monads do allow such a workaround; let’s introduce the Maybe monad and see how the problem practically goes away with very simple code… even if the following definition (which we won&#39;t use) is totally obscure!</p><blockquote>All told, a monad in X is just a monoid in the category of endofunctors of X, with product × replaced by composition of endofunctors and unit set by the identity endofunctor. <a href="https://books.google.com.uy/books?id=MXboNPdTv7QC&amp;pg=PA138&amp;lpg=PA138&amp;dq=%22monoid+in+the+category+of+endofunctors%22+mac+lane&amp;source=bl&amp;ots=feQWTkH2Uw&amp;sig=tv-1JwaMOygKGmFE2vM2FhJVS9o&amp;hl=en&amp;ei=5iWsTJCkBIPSsAPQwJ36Aw&amp;sa=X&amp;oi=book_result&amp;ct=result&amp;redir_esc=y#v=onepage&amp;q&amp;f=false">Saunders Mac Lane</a></blockquote><h3>Dealing with missing values: the MAYBE monad</h3><p>Let’s see our first example. Assume we have a value that may or may not be present. A Maybe can be two different monads:</p><ul><li>A Just (&quot;just a value&quot;) when the value is present</li><li>A Nothing when the value is absent (so it is null or undefined)</li></ul><p>Let’s first see Maybe, which actually is a factory that will produce either Just or Nothing monads.</p><pre>function Maybe(x) {<br>  isEmpty(x)                  // ➊<br>    ? Nothing.call(this)      // ➋<br>    : Just.call(this, x);     // ➌<br>}</pre><p>The isEmpty() function ➊ checks if the passed value is null or undefined; I’ll leave it up to you to code it. When we create a Maybe, depending on the value we pass to it, a Nothing ➋ or a Just ➌ will be created.</p><p>Let’s see the other two monads we need, starting with Just.</p><pre>function Just(x) {<br>  Monad.call(this, x);            // ➊<br>  this.isNothing = () =&gt; false;   // ➋<br>  this.map = (fn) =&gt;              // ➌<br>    new Maybe(fn(x));<br>  this.chain = (fn) =&gt;            // ➍<br>    new Maybe(unwrap(fn(x)));<br>}</pre><p>Since Just extends Monad, we start ➊ by calling the required constructor. We are adding an isNothing() method ➋, so given a Maybe, we can test if it is a Nothing or not; for a Just, isNothing() returns false. The map() ➌ and chain() ➍ methods are similar to what we saw earlier; the difference is that after mapping or chaining, a Maybe is returned instead of a generic Monad.</p><p>We can now look at the Nothing monad.</p><pre>function Nothing() {<br>  Monad.call(this);<br>  this.isNothing = () =&gt; true;         // ➊<br>  this.map = this.chain = () =&gt; this;  // ➋<br>  this.toString= ()=&gt; &quot;Nothing()&quot;;     // ➌<br>}</pre><p>Let’s just highlight the differences with Just. The .isNothing() function here returns true. The .map() and .chain() methods ➋ do nothing at all; they just return the monad itself, ignoring whatever arguments you pass to them. Finally ➌ we must fix the .toString() method because Nothing monads contain no values.</p><p>How would you use a Maybe? The idea is that you get a value, construct a Maybe, and then just chain operations. If the value isn&#39;t empty, the operations will be performed, but otherwise, they will be ignored. The following example shows a simple case. Note we are using <a href="https://medium.com/stackanatomy/forever-functional-pointfree-style-programming-c3877c229ceb">pointfree notation</a>:</p><pre>const plus1 = (x) =&gt; x + 1;    // ➊<br>const times2 = (x) =&gt; 2 * x;<br><br>new Maybe(100)  // ➋<br>  .map(plus1)   // ➌<br>  .map(times2)  // ➍<br>  .toString();  // ➎ Just(202)<br><br>new Maybe(null) // ➏<br>  .map(plus1)<br>  .map(times2)<br>  .toString();  // ➐ Nothing()</pre><p>First ➊ let’s define some simple functions to test our monads. If ➋ you build a Maybe with a nonzero value (100) you can increment it by one ➌ and duplicate the result ➍ and you&#39;ll end ➎ with a Just(202) monad. (Note that we could have used .chain() instead of .map() and it would have produced the same result.) On the other hand, if you start with a null ➏ the operations are ignored, and you end ➐ with a Nothing instead. You didn&#39;t have to write any if statements anywhere; the Maybe, whether a Just or a Nothing works accordingly.</p><blockquote>Note: If you remember it, this is the same we showed when we built our <a href="https://medium.com/stackanatomy/forever-functional-36-d-i-y-booleans-db01d0bbacbb">booleans out of functions</a>! In that case, TRUE and FALSE were functions that dealt differently with whatever you passed to them; here, Just and Nothing work in the same way.</blockquote><h3>Dealing with default values</h3><p>But let’s add to this! You would want to use a default value instead when dealing with possible missing values. You could use isNothing() and write tests, but that wouldn&#39;t use the power of monads! Instead, let&#39;s add an orElse() method to specify what value to use when you get a Nothing. (Of course, orElse() won&#39;t do anything if you got a Just.)</p><pre>function Just(x) {<br>  // ...all previous code, plus:<br><br>  this.orElse = () =&gt; this;          // ➊<br>}<br><br>function Nothing() {<br>  // ...all previous code, plus:<br><br>  this.orElse = (x) =&gt; new Maybe(x); // ➋<br>}</pre><p>The new .orElse() method ➊ won&#39;t do anything for a&#39; Just&#39; monad. Conversely, for a Nothing monad ➋ .orElse() will produce a new Maybe, most likely not a Nothing. (Why would you pass an empty value to the .orElse() method for a Nothing? That would just produce a new Nothing.)</p><p>We can now see examples dealing with missing and default values.</p><pre>new Maybe(1900) // ➊<br>  .orElse(50)   // ➋<br>  .map(plus1)   // ➌<br>  .toString();  // ➍ Just(1901)<br><br>new Maybe(null) // ➎<br>  .orElse(50)   // ➏<br>  .map(plus1)<br>  .toString();  // ➐ Just(51)<br><br>new Maybe(null) // ➑<br>  .map(plus1) <br>  .orElse(50)   // ➒<br>  .toString();  // ➓ Just(50)</pre><p>In the first example ➊ we start with a Just(1900), so orElse() doesn&#39;t do anything ➋ and after incrementing the value by 1 ➌ we end with a Just(1901) ➍. The second case is more interesting; after starting with a Nothing ➎ the orElse() produces a Just(50) ➏ which is then incremented, thus ending ➐ with a Just(51). The third case shows a variation; again, we start with a Nothing, we then use map() (but without any effect), and we apply orElse() ➒ so we finish ➓ with a Just(50); where you place the orElse() makes a difference!</p><h3>A realistic example</h3><p>Let’s go with a real-life example. Assume that, given a customer’s id, we want to show what country he lives in. There are some issues, though:</p><ul><li>The customer id might be wrong</li><li>The customer id could be correct, but he could not have an address field</li><li>The customer could have an address, but without a countryCode field</li><li>The customer could have a countryCode field, but its value might be wrong</li></ul><p>You would usually deal with this by writing many if statements, but the solution is much simpler with Maybe monads. Let&#39;s assume that we have:</p><ul><li>a getCustomer() function that, given an id, returns a Just with the customer&#39;s data (if the customer exists) or a Nothing otherwise</li><li>a countryCodeToName() function that, given a country code, returns the country name, or undefined instead</li><li>a getField() function that, given an object and a field name, returns that field from the object, or null instead. We can easily code const getF = (field)=&gt; (obj) =&gt; obj ? obj[field] : null; for that.</li></ul><p>Now, how can we display the customer’s country name or “N/A” instead? A single line does the job — though we will display in several lines for clarity:</p><pre>getCustomer(22)                 // ➊<br>  .map(getField(&quot;address&quot;))     // ➋<br>  .map(getField(&quot;countryCode&quot;)) // ➌<br>  .map(countryCodeToName)       // ➍<br>  .orElse(&quot;N/A&quot;)                // ➎<br>  .map(console.log);            // ➏</pre><p>Now that we’ve seen a complete example with Maybe monads, let&#39;s consider some extra monads for other cases.</p><h3>Dealing with errors: the EITHER monad</h3><p>When some operation produces an error, we may want more data about it. We’ll create an Either monad, which can be a Left (if there was an error) or a Right (if no error was produced). For instance, a function doing an API call would return a Left or Right monad, depending on how the call went.</p><p>First, let’s look at Either itself, which (as in the case of the Maybe monad) is another factory that produces either Left or Right monads.</p><pre>function Either(l, r) {          // ➊<br>  !isEmpty(l)                    // ➋<br>    ? Left.call(this, l)         // ➌<br>    : Right.call(this, r);       // ➍<br><br>  this.toString =                // ➎<br>    () =&gt; `Either(${l},${r})`;<br>}</pre><p>To create an Either, let&#39;s use the <a href="https://nodejs.org/en/learn/asynchronous-work/javascript-asynchronous-programming-and-callbacks#handling-errors-in-callbacks">&quot;error-first&quot; strategy</a> that Node.js uses. If the first argument is not empty ➋ we assume there was an error, and produce a Left ➌; otherwise the second argument represents data and we use that to produce a Right ➍. We have to override the standard .toString() method ➎ to produce a better description of the object.</p><p>Let’s get into the details. The Left monad (see below) resembles the Nothing one. Instead of a isNothing() function ➊ we&#39;ll have a isLeft() one; we could have called it isError() instead, but I wanted to keep the same naming style. The .map() and .chain() methods ➋ do nothing.</p><pre>function Left(x) {<br>  Monad.call(this, x);                 <br>  this.isLeft = () =&gt; true;           // ➊<br>  this.map = this.chain = () =&gt; this; // ➋<br>}</pre><p>On the other hand, Right is similar to Just. The .isLeft() method logically returns false ➊. The .map() method is more complex, so we&#39;ll just show pseudocode ➋. We have to evaluate fn(x) and check if it produced an error ➋ and, depending on that, return either a Left or a Right. The same type of logic ➌ applies to .chain().</p><pre>function Right(x) {<br>  Monad.call(this, x); <br>  this.isLeft = () =&gt; false;          // ➊<br>  this.map = (fn) =&gt;                  // ➋<br>    // call fn(x) and store it in v<br>    // if fn(x) produced an error e, <br>    // return new Left(e)<br>    // otherwise return new Right(v)<br>  this.chain = (fn) =&gt;                // ➌<br>    // similar to .map() but unwrap v<br>    // when creating the new Right<br>}</pre><p>If you are coding a Node-style callback, which expects error and data parameters, producing an Either is straightforward, along the lines of the code below. Note that you would surely do something with the new Either, not just return it:</p><pre>function someCallback(error, data) {<br>  return new Either(error, data)<br>    // do some operations with the Either<br>}</pre><p>Working with Either is very much the same as with Maybe; the only difference is that when you got a Left you can check its value (with .valueOf()) and use that for whatever you want. Other than that, Left mirrors Nothing, and Right mirrors Just.</p><h3>Recovering from errors</h3><p>How can we recover from issues? We can add a .recover() method; it will do whatever we need when there is an error (when we have a Left) but nothing otherwise (when we have a Right). With Maybe, we wanted to pass a default value to use; here, we had to pass a function to deal with the error. The extra code is as follows:</p><pre>function Left(x) {<br>  // ...all previous code, plus:<br>    <br>  this.recover = (fn) =&gt;               // ➊<br>    // evaluate fn() and store it in v  // ➋<br>    // if it produces an error e,<br>    // return new Left(e)<br>    // otherwise return new Right(v)<br>}<br><br>function Right(x) {<br>  // ...all previous code, plus:<br><br>  this.recover = () =&gt; this;           // ➌<br>}</pre><p>If you got a Left, .recover() will invoke your function ➊ and produce a new Left or Right ➋ based on whatever the function does. Using .recover() with a Right ➌ produces no effect.</p><h3>Dealing with exceptions: the TRY monad</h3><p>We can go further with the previous Either monad. Consider a function that might throw an exception. We can use the Try monad to produce an Either (a Left or a Right) as before. The needed code is shown below:</p><pre>function Try(fn) {<br>  try {<br>    Right.call(this, fn());       // ➊<br>  } catch (e) {<br>    Left.call(this, e.message);   // ➋<br>  }<br>}<br><br>// Or, equivalently:<br><br>function Try(fn) {<br>  try {<br>    Either.call(this, null, fn());<br>  } catch (e) {<br>    Either.call(this, e.message, null);<br>  }<br>}</pre><p>Logic is very simple; we call the fn() function, and if there’s no exception ➊ we return a Right with whatever the function returned, and if an exception e was thrown ➋ we return a Left with the exception. The second alternative implementation does the same, albeit a tad more indirectly.</p><p>Usage is straightforward: We could just rewrite our previous example, which showed a customer’s country, by having getCustomer() return a Try; no further change would be needed.</p><h3>Dealing with future values: Promises</h3><p>We’ve left the simplest example for the end: promises! It so happens that JavaScript’s own promises are already pretty much like monads. We can make do by just modifying Promise.prototype a bit:</p><pre>Promise.prototype.map =<br>  Promise.prototype.chain =<br>    Promise.prototype.then;    // ➊<br><br>Promise.prototype.ap =         // ➋<br>  function(otherPromise) {<br>    return this.map(otherPromise.map);<br>  };</pre><p>There’s an issue; promises always unwrap their values (so if you have a promise that resolves to a promise that resolves to a value, you get just <em>one</em> promise that resolves to a value, not a promise wrapped in another promise, according to <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve">the standard specification</a>) so .map() and .chain() behave the same way, as a synonym for .then().</p><p>We can add an .ap() method with ease ➋ and the code is equivalent to what we saw in <a href="https://fkereki.medium.com/better-error-handling-with-monads-part-1-970076a1d1f4">the previous article for monads</a>; check it out.</p><h3>Conclusion</h3><p>Over these two articles, we have seen what monads are and how they help write simpler, more declarative code. Considering how monads are sometimes explained, a crucial detail is that just focusing on HOW they are built instead of WHAT they are suitable for actually misses the point of having monads at all. The implementation of monads isn’t that complex -we only needed a few lines of vanilla JS- so you can now start taking advantage of them for your own work; go ahead!</p><h3>Further Reading</h3><p>When you start working with monads, error handling naturally leads you to <a href="https://fsharpforfunandprofit.com/rop/">“Railway Oriented Programming”</a> ( <a href="https://vimeo.com/113707214">see video here</a>); read more on this!</p><p><em>If you want to read about programming (including functional programming, of course), algorithms in general, and data structures and their applications, take a look at my </em><a href="https://www.amazon.com/Structures-Algorithms-JavaScript-Federico-Kereki/dp/1718502621/ref=sr_1_3"><em>DATA STRUCTURES AND ALGORITHMS IN JAVASCRIPT</em></a><em> and </em><a href="https://www.amazon.com/Mastering-JavaScript-Functional-Programming-maintainable/dp/1804610135/ref=sr_1_5"><em>MASTERING JAVASCRIPT FUNCTIONAL PROGRAMMING</em></a><em> books.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/779/1*NOWSsSbVG71zNQb5QXbn8Q.png" /></figure><p><em>Originally published at </em><a href="https://blog.openreplay.com/forever-functional-better-error-handling-with-monads--part-2/"><em>https://blog.openreplay.com</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ca05e20e3a14" width="1" height="1" alt=""><hr><p><a href="https://medium.com/stackanatomy/better-error-handling-with-monads-part-2-ca05e20e3a14">Forever Functional #41 —  Better Error Handling with Monads (Part 2)</a> was originally published in <a href="https://medium.com/stackanatomy">StackAnatomy</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Forever Functional #37 — Can AI do that?]]></title>
            <link>https://medium.com/stackanatomy/forever-functional-37-can-ai-do-that-2d32250e05c9?source=rss----48c8bfd9e724---4</link>
            <guid isPermaLink="false">https://medium.com/p/2d32250e05c9</guid>
            <category><![CDATA[turing-test]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[algorithms]]></category>
            <category><![CDATA[undecidability]]></category>
            <category><![CDATA[machine-learning]]></category>
            <dc:creator><![CDATA[Federico Kereki]]></dc:creator>
            <pubDate>Mon, 29 Apr 2024 22:13:09 GMT</pubDate>
            <atom:updated>2026-03-07T15:55:15.951Z</atom:updated>
            <content:encoded><![CDATA[<h3>Forever Functional #37 — Can AI do that?</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*SGszV9D28zZtCWsm.png" /></figure><p><em>Given the advances in </em><a href="https://en.wikipedia.org/wiki/Artificial_intelligence"><em>Artificial Intelligence</em></a><em> (AI), often coupled with </em><a href="https://en.wikipedia.org/wiki/Machine_learning"><em>Machine Learning</em></a><em> (ML), which have provided us with tools like </em><a href="https://chat.openai.com/"><em>ChatGPT</em></a><em> and others, the question pops up again: Is there anything AI cannot do? Can AI do anything we can think of? This article will consider that question, look at an interesting problem, and see whether AI can handle it.</em></p><h3>An old question</h3><p>The idea that machines could do everything dates back to <a href="https://en.wikipedia.org/wiki/Alan_Turing">Alan Turing</a>, the English mathematician who was key to breaking German secret codes during World War II, as shown in the movie <a href="https://www.imdb.com/title/tt2084970/">“<em>The Imitation Game</em>”</a>. Back in 1950 (many years before we had computers even minimally approaching the power and capabilities of modern ones), he wrote a paper, <a href="https://redirect.cs.umbc.edu/courses/471/papers/turing.pdf">“<em>Computing Machinery and Intelligence</em>”</a>, in which he considered the question, “Can machines think?” The paper is very interesting and defined a test (“<em>Turing’s Test</em>”) by which it could be possible to decide whether machines can be said to think.</p><p><em>In the article, Turing considered </em><a href="https://en.wikipedia.org/wiki/Computing_Machinery_and_Intelligence#Nine_common_objections"><em>nine possible objections</em></a><em> and finally decided it was possible that machines could think, but not at that time. The article also discussed what is meant by “thinking”!</em></p><p>If we want to consider that question, it seems that our question, “<em>Can AI do that?</em>” (meaning, anything we can dream of, and in particular, thinking) could have a positive answer, though it’s still pending… so we’re left with an uncertainty. Let’s consider instead a rather simpler question, whose answer could be a boon to developers, mathematicians, logicians, and more!</p><h3>A simpler (?) question</h3><p>Instead of thinking about machines being able to do any task requiring intelligence, or about thinking in particular, let’s focus on a single issue: given a program, can we decide whether it works or not? This is very ambitious because we should be able to specify what programs should produce for every possible input, so let’s tone down the question a bit. Instead of that very general first question, let’s just think about applying AI to detect whether a function may end in an infinite loop. If a function loops forever, we’re certain the function is not correct, so at least that’s a good step forward. We may not know if a function works well, but we may be sure if it doesn’t.</p><p><em>An aside: if we could decide whether a function will always stop, we’d be able to prove mathematical theorems very simply! For instance, suppose we wanted to see whether the </em><a href="https://en.wikipedia.org/wiki/Goldbach%27s_conjecture"><em>Goldbach Conjecture</em></a><em> (which says that every even number greater than 2 can be expressed as the sum of two prime numbers) is true. We could write a </em><em>goldbachTest() function that would test if the conjecture was true for ever-increasing values 4, 6, 8, 10... etc., stopping only if the conjecture failed for some value. If we applied our &quot;loop detection&quot; function to </em><em>goldbachTest, and it said that the function would loop forever, we&#39;d know the conjecture was true, and false otherwise!</em></p><p>Let’s start thinking about our problem, detecting whether functions are “infinite-loop-less” or not. Is this possible? For at least some functions, the answer is “yes”. For example, if you consider functions that do not include looping statements (while, for) and do not call other functions (or themselves, using recursion), we can be sure they must always end. Furthermore, recognizing these very special &quot;linear&quot; functions could be done by a program that wouldn&#39;t even need AI; you can write it with ease.</p><p>However, we want to be able to work with any function and see whether it may enter an infinite loop. What about using AI and ML to detect them? For example, how do we teach a machine to recognize cats? An ML method is based on processing many images, some of which show cats and some do not. Eventually, a decision engine “learns” to distinguish cats from non-cats, and this has been done many times.</p><p>In that way, we could think of teaching a machine to recognize looping functions by feeding it with lots of different functions, some of which are loopless and some of which are not, and hope that the ML method produces our desired result: an algorithm capable of deciding whether any function may or may not enter an infinite loop. But would this work?</p><h3>A paradoxical limit</h3><p>The ML idea is there, and we know it can work, at least for some problems; could it work for ours? Let’s suppose it would: our process would end by producing our desired willLoop(fn) function that, given any fn function, would precisely return either true (if the function could enter an infinite loop) or false (if the function would always be guaranteed to finish).</p><p>But the (assumed) existence of this willLoop function implies an inevitable paradox! To see it, imagine we wrote a mystery(fn) function as shown below:</p><pre>function mystery(fn) {<br>  if (willLoop(fn)) {<br>    return true;<br>  } else {<br>    while (true) { <br>      /* loop forever! */<br>    }<br>  }<br>}</pre><p>What does mystery do? Given a fn function, if:</p><ul><li>fn will loop in some case, mystery returns true</li><li>fn will never loop, mystery enters an infinite loop</li></ul><p>And now, the big question: what happens if we call mystery, giving the mystery function itself as its parameter?</p><p><em>Don’t object to the idea of feeding a function with its own code. For instance, </em><a href="https://prettier.io/"><em>Prettier</em></a><em> is written in JavaScript, and we can use Prettier to format itself. Similarly, we can use </em><a href="https://eslint.org/"><em>ESLint</em></a><em> to detect problems in its own code. Even if it may be a bit unusual, in principle, there’s no objection to calling a function with its own code as an argument.</em></p><p>Let’s analyze what happens if we call mystery(mystery).</p><ul><li>if willLoop(mystery) returns true (meaning that mystery will loop forever), then mystery will return a value and finish, but</li><li>if willLoop(mystery) returns false (meaning that mystery will never loop), then mystery will enter an infinite loop.</li></ul><p>This is contradictory! There’s no way out of this paradox (similar to Bertrand Russell’s <a href="https://en.wikipedia.org/wiki/Barber_paradox">“<em>Barber Paradox</em>”</a>) other than deciding that mystery cannot exist, and this implies that willLoop cannot exist either... pity!</p><p><em>In computability theory, we would say that our problem, detecting whether functions may or may not enter an infinite loop, is </em><a href="https://en.wikipedia.org/wiki/Undecidable_problem">undecidable</a><em>. The </em><a href="https://en.wikipedia.org/wiki/Halting_problem"><em>“Halting Problem”</em></a><em> was shown in 1936 to be another undecidable problem; Alan Turing later provided a different proof of the fact.</em></p><h3>Conclusion</h3><p>The limits and capabilities of AI, based on ML or not, are clearly growing every day, and we don’t yet know how far they may go. However, as we have shown here, applying AI and ML to the problem of deciding if a function may enter an infinite loop is unrealistic and cannot succeed without producing an impossible logical paradox.</p><p>There are limits to AI, after all!</p><p><em>If you want to read about programming (including functional programming, of course), algorithms in general, and data structures and their applications, take a look at my </em><a href="https://www.amazon.com/Structures-Algorithms-JavaScript-Federico-Kereki/dp/1718502621/ref=sr_1_3"><em>DATA STRUCTURES AND ALGORITHMS IN JAVASCRIPT</em></a><em> and </em><a href="https://www.amazon.com/Mastering-JavaScript-Functional-Programming-maintainable/dp/1804610135/ref=sr_1_5"><em>MASTERING JAVASCRIPT FUNCTIONAL PROGRAMMING</em></a><em> books.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/779/1*NOWSsSbVG71zNQb5QXbn8Q.png" /></figure><p><em>Originally published at </em><a href="https://blog.openreplay.com/forever-functional-can-ai-do-that/"><em>https://blog.openreplay.com</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2d32250e05c9" width="1" height="1" alt=""><hr><p><a href="https://medium.com/stackanatomy/forever-functional-37-can-ai-do-that-2d32250e05c9">Forever Functional #37 — Can AI do that?</a> was originally published in <a href="https://medium.com/stackanatomy">StackAnatomy</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Forever Functional #36 — D.I.Y. Booleans?]]></title>
            <link>https://medium.com/stackanatomy/forever-functional-36-d-i-y-booleans-db01d0bbacbb?source=rss----48c8bfd9e724---4</link>
            <guid isPermaLink="false">https://medium.com/p/db01d0bbacbb</guid>
            <category><![CDATA[javascript-tips]]></category>
            <category><![CDATA[functional-programming]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[logic]]></category>
            <dc:creator><![CDATA[Federico Kereki]]></dc:creator>
            <pubDate>Thu, 29 Feb 2024 11:30:58 GMT</pubDate>
            <atom:updated>2026-03-07T15:49:09.162Z</atom:updated>
            <content:encoded><![CDATA[<h3>Forever Functional #36 — D.I.Y. Booleans?</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*KXEsb6Bu2B4uhLbX.png" /></figure><blockquote>Could you program if you didn’t have booleans? What about lacking and, or, and other operators? Would you be able to cope without if or while statements? Functional Programming is very powerful, and in this article, we&#39;ll see how we can make our own booleans in a fully functional way.</blockquote><p>What do we use boolean values for? The answer is simple: to pick one thing or another. For instance, in an if statement, you do one thing or another depending on the value. If we can only work with functions, we will represent a boolean value by a function; there is no other option!</p><p>Given two values, the boolean function that represents “true” returns the first. Similarly, given two values, the boolean function that represents “false” will return the second. We can write:</p><pre>const TRUE  = (trueValue, falseValue) =&gt; trueValue;<br>const FALSE = (trueValue, falseValue) =&gt; falseValue;</pre><p>Can we do something with these? Let’s start with something simple, to get used to these values gradually. We can write a toString() function to transform the boolean value into a string.</p><pre>const toString = boolValue =&gt; boolValue(&quot;T&quot;, &quot;F&quot;);<br><br>console.log(toString(TRUE));   // &quot;T&quot;<br>console.log(toString(FALSE));  // &quot;F&quot;</pre><p>In our implementation, boolean expressions will always be evaluated as TRUE or FALSE.</p><h3>Writing our boolean operators</h3><p>OK, we now have the most basic values, TRUE and FALSE. But, if we had no booleans, we would not have any boolean operators either! So, what can we do? Let’s start with the simplest one.</p><h4>The “not” operator</h4><p>The first operator we’ll work out is the equivalent of JavaScript’s !: given a boolean value x, we want to write something corresponding to !x.</p><pre>const NOT = (X) =&gt; X(FALSE, TRUE);</pre><p>How does this work? Keep in mind that a boolean value is now a function that receives two values and returns the first if the boolean value represents “true” or the second if it represents “false”. Here, we pass FALSE and TRUE as values, so if the boolean value represents “true”, FALSE will be returned, and if the value represents “false”, TRUE will be the result. We can test this quickly:</p><pre>console.log(toString(NOT(TRUE)));  // &quot;F&quot;<br>console.log(toString(NOT(FALSE))); // &quot;T&quot;</pre><p>Study this carefully, and make sure you understand how this works because the following operators are a bit more involved but require the same kind of thinking.</p><h4>The “or” operator</h4><p>Let’s create a version of the “OR” (||) operator, so given two boolean values, X and Y, we can write something equivalent to X||Y. First, we must remember how the operation works; check its <a href="https://en.wikipedia.org/wiki/Truth_table">truth table</a> below.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/829/1*KuBHqcZDCEx0VW6b183-Fg.png" /><figcaption>The truth table for the OR operator</figcaption></figure><p>Checking the table above, we can say that:</p><ul><li>if X is TRUE, the result is TRUE, no matter what Y is.</li><li>if X is FALSE, the result matches the value of Y.</li></ul><p>We can transform this into code:</p><pre>const OR = (X, Y) =&gt; X(TRUE, Y);</pre><p>Let’s work this out, which is more involved! Suppose X represents TRUE. In that case, it will return the first argument it&#39;s given (in this case, TRUE), so when X is TRUE, OR(X, Y) is also TRUE. On the other hand, if X is FALSE, it will return the second argument it&#39;s given (here, Y), so in that case, OR(X, Y) will equal Y. Everything is according to our analysis of the table above.</p><h4>The “and” operator</h4><p>Let’s move on to the “AND” (&amp;&amp;) operator, so given x and y we can calculate x &amp;&amp; y. The truth table for it is as follows.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/829/1*UeItYw97cdsgEfUCjvccuA.png" /><figcaption>The truth table for the AND operator</figcaption></figure><p>In summary:</p><ul><li>if X is FALSE, the result is FALSE no matter what Y is.</li><li>if X is TRUE, the result matches the value of Y.</li></ul><p>This is transformed directly into code:</p><pre>const AND = (X, Y) =&gt; X(Y, FALSE);</pre><p>This analysis is very similar to what we did for OR. Without going into much detail, if X is TRUE, it will return the first argument it&#39;s given (so, Y), and if X is FALSE, the AND will be FALSE; again, the working of this function matches our analysis.</p><blockquote>By the way, you could also implement (more mysteriously) OR = (X,Y) =&gt; X(X,Y) and AND = (X,Y) =&gt; X(Y,X); can you work out why? See the last section of the article for these and other questions.</blockquote><h4>Operators for circuit building</h4><p>We’re on a roll! Let’s go for some other operators. In electronic circuit design NOR and NAND logic gates are frequently used. (Why? This has to do with the concept of <a href="https://www.allaboutcircuits.com/textbook/digital/chpt-3/gate-universality/">&quot;universal operators&quot;</a>, but we won&#39;t go into that here. NAND is also known as the <a href="https://en.wikipedia.org/wiki/Sheffer_stroke">&quot;Sheffer stroke&quot;</a>, X↑Y, and NOR as the <a href="https://en.wikipedia.org/wiki/Logical_NOR">&quot;Webb Operator&quot;</a>, X↓Y.)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/829/1*YZB0nNn89VKmpZXh8coAEA.png" /><figcaption>The truth table for the NOR and NAND operators</figcaption></figure><p>The definitions are simple:</p><ul><li>X NOR Y is just the negation of X OR Y, so !(X || Y), equivalent to !X&amp;&amp;!Y.</li><li>Similarly, X NAND Y is the negation of X AND Y, so !(X &amp;&amp; Y) or, equivalently, !X||!Y.</li></ul><pre>const NOR  = (X, Y) =&gt; NOT(OR(X, Y));<br>const NAND = (X, Y) =&gt; NOT(AND(X, Y));</pre><p>We won’t go into details; after all, the code fully matches the definitions we gave above, and it’s easy to verify they work correctly.</p><h4>Other operators</h4><p>So far, we’ve been able to transform several JavaScript operators into our functional style. What about some other operators that are less commonly used? The three we will see are:</p><ul><li>X XOR Y, exclusive OR (but not the bitwise ^ operator). This is written as X⊕Y or X⊻Y in boolean algebra.</li><li>X EQU Y, equivalence, usually written as X↔Y or X≡Y</li><li>X IMP Y, implication, written as X⊃Y or X⇒Y</li></ul><p>The following table resumes the trio.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/829/1*kUpwMwoDMDv03SssSZHJ9g.png" /><figcaption>The truth table for the XOR, EQU, and IMP operators</figcaption></figure><p>We can note:</p><ul><li>The results of X XOR Y and X EQU Y are always the opposite.</li><li>X XOR Y is equivalent to X !== Y or, equivalently, (X &amp;&amp; !Y) || (!X &amp;&amp; Y)... uglier!</li><li>X EQU Y is equivalent to X === Y or (X &amp;&amp; Y) || (!X &amp;&amp; !Y)</li><li>X IMP Y is always true unless X is TRUE and Y is FALSE, so !X || Y. (Check it out!)</li></ul><pre>const XOR = (X, Y) =&gt; X(NOT(Y), Y); <br>const EQU = (X, Y) =&gt; X(Y, NOT(Y)); <br>const IMP = (X, Y) =&gt; X(Y, TRUE); </pre><p>Can you see how these work? Going directly to the definitions is best. For instance, let’s see XOR: if X is TRUE, then the result will be NOT(Y), and if X is FALSE, the result will be Y, as we saw earlier. (I&#39;ll leave the other two expressions to you.) The match between the boolean algebraic definitions and the actual JavaScript code gives us a lot of confidence in the validity of the results.</p><h3>Writing conditional statements</h3><p>We now have functional equivalents to boolean values, but what about using them? After all, the standard if and while JavaScript statements are not designed to work with our invented values. We will have to show that we can write our alternative implementations of both statements so we will be able to code anything we want to.</p><h4>Writing our if statements</h4><p>Now, what would an if look like? It would be a function (naturally! we only have functions!) with three parameters:</p><ul><li>booleanFn, a function that returns a boolean value</li><li>thenFn, a function to be executed if the boolean value means &quot;true&quot;</li><li>elseFn, a function to be executed if the boolean value means &quot;false&quot;</li></ul><p>(Why are we providing functions? We don’t want anything to be evaluated unless it’s necessary. For example, if the boolean value is evaluated as TRUE, we will then evaluate thenFn() and ignore elseFn(); we will only evaluate what we really need.)</p><p>We would then write:</p><pre>const ifThenElse = (booleanFn, thenFn, elseFn) =&gt;<br>  booleanFn()(thenFn, elseFn)();</pre><p>For example, let’s write a statement that will print out “AM” or “PM” depending on the time of the day. Let’s assume an isMorning() function that returns a TRUE boolean value in the morning and a FALSE one in the afternoon.</p><pre>const printAM = () =&gt; console.log(&quot;It&#39;s AM&quot;);<br>const printPM = () =&gt; console.log(&quot;It&#39;s PM&quot;);<br><br>ifThenElse(isMorning, printAM, printPM);  // AM or PM as it may be</pre><p>The isMorning() function would be written as follows. Keep in mind this is a very simple example; in reality, the evaluation could be much longer and more complex:</p><pre>const isMorning = () =&gt;<br>  new Date().getHours() &lt; 12 ? TRUE : FALSE;</pre><p>Why are we writing this using the ternary operator? The reason is that in a purely functional language, any test would return either TRUE or FALSE, our functions, but in JavaScript (which, after all, <em>does</em> have booleans!) we have to do the conversion ourselves.</p><h4>Writing a while loop</h4><p>We’re almost done; we managed to write basic TRUE and FALSE values, implemented several boolean operators, and also have an if alternative; we only need a while equivalent for looping, and we&#39;ll have all the tools we could ever need.</p><p>This will be a tad trickier than the if code. In Functional Programming, instead of loops, we use recursion. The functional way of doing a while loop would be the following.</p><pre>const whileLoop = (booleanFn, loopFn) =&gt;<br>  booleanFn()(<br>    () =&gt; {<br>      loopFn();<br>      whileLoop(booleanFn, loopFn);<br>    },<br>    () =&gt; {}<br>  )();</pre><p>Let’s start by describing the parameters of the whileLoop() function.</p><ul><li>booleanFn is, as in the if implementation, a function that will return a boolean value</li><li>loopFn is a function that will be executed in every pass of the loop, as long as the evaluated boolean value is TRUE.</li></ul><p>How does this work? If booleanFn() evaluates to TRUE, the first argument to the function will be evaluated - it will execute loopFn() and recursively call itself again. On the other hand, when booleanFn() evaluates to FALSE, a &quot;no operation&quot; function will be executed, and the loop will end; good!</p><p>Let’s finish with a short example showing a countdown loop.</p><pre>let number = 5;<br>const checkPositive = () =&gt; MakeBool(number &gt; 0);<br>const loopFn = () =&gt; console.log(number--);<br>whileLoop(checkPositive, loopFn); // 5 4 3 2 1 in that order</pre><p>Can you follow how this works? The part that’s usually harder to understand is the usage of recursion to do the looping; after you wrap your head around that, the rest follows quickly.</p><h3>Conclusion</h3><p>We started this article by wondering what we would do if we had to code without having boolean values and operators, and also lacking basic flow statements like if and while. By applying functional programming ideas, we were first able to produce our own TRUE and FALSE equivalents. We then added several operators to be able to build complex expressions, and we finally produced functional versions for if and while statements.</p><p>Initially, it seemed like we were getting into an impossible situation, but we solved all the issues. Of course, working with JavaScript, you wouldn’t do this — why would you? After all, booleans are an integral part of the language, so there’s no need to do all this rigmarole to get what you already have!</p><p>The article&#39;s objective was to help you widen your horizons and realize that Functional Programming goes even further than letting you use functions in some ways; it allows you to elegantly express many concepts and operations, all with the same basic tools—impressive!</p><p>I cannot say it better: as it reads in <a href="http://www.usrsb.in/Building-Data-Structures-from-Functions.html">an article by Alex Beal</a>,</p><blockquote>“In the end, this might strike you as nothing more than a useless programming trick. In a sense that’s right. I’d never use this in my own code. What makes this technique so valuable is that it actually fits into the broader context of lambda calculus<em> […] </em>In the language of lambda calculus, you’re given only a very basic set of tools.<em> […] </em>Incredibly, it turns out that that’s all you need.”</blockquote><h3>References</h3><p>If you want to learn more about the techniques we used here, you should read about <a href="https://en.wikipedia.org/wiki/Church_encoding">Church Encoding</a> and <a href="https://en.wikipedia.org/wiki/Mogensen%E2%80%93Scott_encoding">Scott Encoding</a>; both representations are the same for boolean values.</p><h3>In the mood for some questions?</h3><p>If you want to experiment a bit more, try your hand with these questions.</p><p>#1. Show that these OR versions are equivalent to the one we wrote.</p><pre>const OR1  = (left, right) =&gt; left(left, right);<br>const OR2  = (left, right) =&gt; right(right, left);</pre><p>#2. Do the same for these alternatives to our AND.</p><pre>const AND1 = (left, right) =&gt; left(right, left);<br>const AND2 = (left, right) =&gt; right(left, right);</pre><p>#3. Show that if X is a boolean value, X(Y,Z) is equivalent to (X &amp;&amp; Y) || (!X &amp;&amp; Z).</p><p>#4. Using the previous result, prove that our NOT, OR, AND, etc., definitions are correct.</p><p>#5. Show that our implementations of AND and OR also apply JavaScript&#39;s <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_AND#short-circuit_evaluation">&quot;short circuit&quot;</a> evaluation rules.</p><p>#6. Do the alternative versions for AND and OR from questions #1 and #2 also apply short circuit evaluation like JavaScript?</p><p>#7. Can you modify ifThenElse(...) so its third parameter will be optional?</p><p>#8. After implementing the change in the previous question, can you shorten whileLoop(...) to use ifThenElse(...) and take advantage of the optional parameter?</p><p>Check the complete series of articles on Functional Programming and JavaScript:</p><p><a href="https://medium.com/stackanatomy/forever-functional-the-series-616ad90645b4">https://medium.com/stackanatomy/forever-functional-the-series-616ad90645b4</a></p><p><em>If you want to read about programming (including functional programming, of course), algorithms in general, and data structures and their applications, take a look at my </em><a href="https://www.amazon.com/Structures-Algorithms-JavaScript-Federico-Kereki/dp/1718502621/ref=sr_1_3"><em>DATA STRUCTURES AND ALGORITHMS IN JAVASCRIPT</em></a><em> and </em><a href="https://www.amazon.com/Mastering-JavaScript-Functional-Programming-maintainable/dp/1804610135/ref=sr_1_5"><em>MASTERING JAVASCRIPT FUNCTIONAL PROGRAMMING</em></a><em> books.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/779/1*NOWSsSbVG71zNQb5QXbn8Q.png" /></figure><p><em>Originally published at </em><a href="https://blog.openreplay.com/forever-function-diy-booleans/"><em>https://blog.openreplay.com</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=db01d0bbacbb" width="1" height="1" alt=""><hr><p><a href="https://medium.com/stackanatomy/forever-functional-36-d-i-y-booleans-db01d0bbacbb">Forever Functional #36 — D.I.Y. Booleans?</a> was originally published in <a href="https://medium.com/stackanatomy">StackAnatomy</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Forever Functional #34 — Maximize JavaScript’s Performance WITHOUT Transducers]]></title>
            <link>https://medium.com/stackanatomy/forever-functional-maximize-javascripts-performance-without-transducers-bebf9dab3471?source=rss----48c8bfd9e724---4</link>
            <guid isPermaLink="false">https://medium.com/p/bebf9dab3471</guid>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[functional-programming]]></category>
            <category><![CDATA[transducers]]></category>
            <category><![CDATA[algorithms]]></category>
            <dc:creator><![CDATA[Federico Kereki]]></dc:creator>
            <pubDate>Tue, 19 Dec 2023 22:21:23 GMT</pubDate>
            <atom:updated>2025-06-28T23:16:09.603Z</atom:updated>
            <content:encoded><![CDATA[<h3>Forever Functional #34 — Maximize JavaScript’s Performance WITHOUT Transducers</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/748/0*TMlB0LdDBJyvbky3.png" /></figure><blockquote>In the <a href="https://medium.com/stackanatomy/forever-functional-maximize-javascripts-performance-with-transducers-f0a866d000c0">previous article on transducers</a> we saw a way to optimize long sequences of operations on arrays, but the solution wasn’t that trivial. Many readers wondered whether we could achieve the same result more simply, and this article will tackle that: we won’t use transducers (as we did before) but with the help of some functional programming, we’ll get equally good solutions.</blockquote><p>Let’s remember our original problem — which was a trivial example meant to highlight the issues we had. We had an array, and we wanted to (1) take only odd values, (2) duplicate them, (3) keep values under 50, and (4) add 3 to them. The following code achieved this:</p><pre>const testOdd = (x) =&gt; x % 2 === 1;<br>const duplicate = (x) =&gt; x + x;<br>const testUnderFifty = (x) =&gt; x &lt; 50;<br>const addThree = (x) =&gt; x + 3;<br><br>const myArray = [22, 9, 60, 24, 11, 63];<br><br>const newArray = myArray<br>  .filter(testOdd)<br>  .map(duplicate)<br>  .filter(testUnderFifty)<br>  .map(addThree``<br>console.log(newArray); // [21,25]</pre><p>What’s the problem here? Every time you apply an operation, a new intermediate array is created, and with large amounts of data, the extra time may be significant.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/492/0*XZSigruyGKvw8ed6.png" /></figure><p>In the previous article, we described a solution based on trying to go array element by array element and applying all transformations in order, and we developed transducers for that. But we may make do with something simpler! Let’s see that.</p><h3>A first (but not too good) solution</h3><p>Our example was straightforward, and some readers objected by reasoning that it was pretty clear that the only values of the original array that we’d pick would be odd ones, under 25, and then we would duplicate them and add three, so a simple loop could do the job… and we wouldn’t even need the original four functions we used!</p><pre>const simplifiedPass = (someArray) =&gt; {<br>  const result = [];<br>  someArray.forEach((value) =&gt; {<br>    if (value % 2 &amp;&amp; value &lt; 25) {<br>      result.push(value * 2 + 3);<br>    }<br>  });<br>  return result;<br>};<br><br>const newArray2 = simplifiedPass(myArray);<br>console.log(newArray2);</pre><p>This works and is perfectly correct — but it’s hard to generalize. With our simple example, deducing which numbers would be processed was easy, but in real life, the logical checks could be very complex, and you wouldn’t be able to reduce them to a single test as we did here. So, while this shows that optimization is doable, the method itself cannot be applied in every case; we need a more general solution.</p><h3>A second (also handcrafted) solution</h3><p>As in the previous case, we can do better by going element by element and applying maps and filters in sequence.</p><pre>const singlePassFourOps = (someArray) =&gt; {<br>  const result = [];<br>  someArray.forEach((value) =&gt; {<br>    let ok = false; // ①<br>    if (testOdd(value)) {<br>      value = duplicate(value);<br>      if (testUnderFifty(value)) {<br>        value = addThree(value);<br>        ok = true;<br>      }<br>    }<br>    if (ok) { // ②<br>      result.push(value);<br>    }<br>  });<br>  return result;<br>};<br><br>const newArray3 = singlePassFourOps(myArray);<br>console.log(newArray3); // [ 21,25 ]</pre><p>We use an ok variable ① to learn if a value from the original array passed all tests ②. Each filter() is transformed into an if, and each map() updates value. If we reach the end of the operations, we set ok to true, which means we&#39;ll push the final value into the result array. This works! However, we had to write a function from scratch, and we may be able to achieve a more general solution.</p><h3>A third (and more general) solution</h3><p>The previous code requires writing a function for each set of transformations. However, what about passing all the mapping and filtering functions in an array? This would mean we could write a general function that could deal with any combination of filters and maps.</p><p>There’s a problem, though: how will we know whether a function in the array is meant to be a filter or a map? Let’s have an array with pairs of values: first an “M” or “F”, meaning “map” or “filter”, and then the function itself. Testing the first value of the pair will let us know what to do with the second value, the function.</p><pre>const singlePassManyOps = (someArray, fnList) =&gt; {<br>  const result = [];<br>  someArray.forEach((value) =&gt; {  // ①<br>    if (<br>      fnList.every(([type, fn]) =&gt; {  // ②<br>        if (type === &quot;M&quot;) { // ③<br>          value = fn(value);<br>          return true;<br>        } else {<br>          return fn(value); // ④<br>        }<br>      })<br>    ) {<br>      result.push(value);<br>    }<br>  });<br>  return result;<br>};<br><br>const newArray4 = singlePassManyOps(myArray, [<br>  [&quot;F&quot;, testOdd],<br>  [&quot;M&quot;, duplicate],<br>  [&quot;F&quot;, testUnderFifty],<br>  [&quot;M&quot;, addThree],<br>]);<br>console.log(newArray4);</pre><p>This works: we go through the array, element by element ①. For each function in the array ②, if it’s a map ③ we update value, and otherwise we test whether to go on or not ④. Why are we using every() instead of foreach()? The key is that we want to stop going through the array of functions as soon as a filter fails, but foreach() doesn&#39;t have a nice way to stop the loop. On the other hand, every() stops looping as soon as a false result is encountered - which will happen if a filtering function returns false. (And, by the way, that&#39;s why we return true after a mapping, so every() won&#39;t stop.) This is going better! Can we make it simpler?</p><h3>A fourth (and simpler) solution</h3><p>We can simplify the work by writing a pair of functions to help us produce the needed array; given a function, they will produce the right pair of values.</p><pre>const applyMap = (fn) =&gt; [&quot;M&quot;, fn];<br>const applyFilter = (fn) =&gt; [&quot;F&quot;, fn];</pre><p>With these functions, we can change the code above to the following.</p><pre>const newArray5 = singlePassManyOps(myArray, [<br>  applyFilter(testOdd),<br>  applyMap(duplicate),<br>  applyFilter(testUnderFifty),<br>  applyMap(addThree),<br>]);<br>console.log(newArray5);</pre><p>This is nicer, and also declarative in aspect: you clearly see we first apply a filter ( testOdd), then a map ( duplicate), etc., in the same sequence as in our original code. Also, performance is optimal; we don&#39;t have any intermediate arrays, and we don&#39;t perform any unnecessary filters or maps. We&#39;re done! However...</p><h3>The fifth (and definitive) solution</h3><p>In the previous article, we mentioned we wouldn’t always want to finish by producing an array; we could want to apply a final reduce() operation. We can fix this by making the initial value of result and the function that updates it optional, with predefined default values.</p><pre>const singlePassMoreGeneral = (<br>  someArray,<br>  fnList,<br>  initialAccum = [],<br>  reduceAccumFn = (accum, value) =&gt; {<br>    accum.push(value);<br>    return accum;<br>  }<br>) =&gt; {<br>  let result = initialAccum;      // ①<br>  someArray.forEach((value) =&gt; {<br>    if (<br>      fnList.every(([type, fn]) =&gt; {<br>        if (type === &quot;M&quot;) {<br>          value = fn(value);<br>          return true;<br>        } else {<br>          return fn(value);<br>        }<br>      })<br>    ) {<br>      result = reduceAccumFn(result, value); // ②<br>    }<br>  });<br>  return result;<br>};<br><br>const newArray6 = singlePassMoreGeneral(myArray, [<br>  applyFilter(testOdd),<br>  applyMap(duplicate),<br>  applyFilter(testUnderFifty),<br>  applyMap(addThree),<br>]);<br>console.log(newArray6);</pre><p>Apart from adding initialAccum (the initial value of the accumulator for the reducing operation) and reduceAccumFn (the reducer function itself) the other changes are the initial value for result ① and the way result is updated ②.</p><p>We can test the code by finding the sum of the final values.</p><pre>const newValue = singlePassMoreGeneral(<br>  myArray,<br>  [<br>    applyFilter(testOdd),<br>    applyMap(duplicate),<br>    applyFilter(testUnderFifty),<br>    applyMap(addThree),<br>  ],<br>  0,<br>  (x, y) =&gt; x + y<br>);<br>console.log(newValue);</pre><p>This worked! We can now apply any sequence of mapping and filtering operations optimally, optionally finishing with a reducing step if desired.</p><h3>Summary</h3><p>We started the article trying to find a simpler, though equally powerful, way of optimizing a sequence of operations on a large array. We went from a very simple solution, which wasn’t general enough, to a final solution that’s fully equivalent to the transducers’ one, although arguably easier to understand, despite also using functional programming in many ways. This goes to show the validity of the idea that “there’s more than one way to skin a cat”- or, in our case, “to optimize array processes”!</p><p><em>Don´t miss the first part of this article, in which we used transducers to solve the problem.</em></p><p><a href="https://medium.com/stackanatomy/forever-functional-maximize-javascripts-performance-with-transducers-f0a866d000c0">Forever Functional #32 — Maximize JavaScript’s Performance With Transducers</a></p><p><em>Also, check the next article, which shows how we optimized the transducer-less solution to greater performance.</em></p><p><a href="https://medium.com/stackanatomy/forever-functional-35-optimizing-javascript-which-way-b51ae420b600">Forever Functional #35 — Optimizing JavaScript… Which Way?</a></p><p><em>If you want to read about programming (including functional programming, of course), algorithms in general, and data structures and their applications, take a look at my </em><a href="https://www.amazon.com/Structures-Algorithms-JavaScript-Federico-Kereki/dp/1718502621/ref=sr_1_3"><em>DATA STRUCTURES AND ALGORITHMS IN JAVASCRIPT</em></a><em> and </em><a href="https://www.amazon.com/Mastering-JavaScript-Functional-Programming-maintainable/dp/1804610135/ref=sr_1_5"><em>MASTERING JAVASCRIPT FUNCTIONAL PROGRAMMING</em></a><em> books.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/779/1*NOWSsSbVG71zNQb5QXbn8Q.png" /></figure><p><em>Originally published at </em><a href="https://blog.openreplay.com/forever-functional-maximize-javascript-performance-without-transducers/"><em>https://blog.openreplay.com</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=bebf9dab3471" width="1" height="1" alt=""><hr><p><a href="https://medium.com/stackanatomy/forever-functional-maximize-javascripts-performance-without-transducers-bebf9dab3471">Forever Functional #34 — Maximize JavaScript’s Performance WITHOUT Transducers</a> was originally published in <a href="https://medium.com/stackanatomy">StackAnatomy</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Forever Functional #33 — Complex Typing in TypeScript, Part 2]]></title>
            <link>https://medium.com/stackanatomy/forever-functional-complex-typing-in-typescript-part-2-ad5bdb274d6e?source=rss----48c8bfd9e724---4</link>
            <guid isPermaLink="false">https://medium.com/p/ad5bdb274d6e</guid>
            <category><![CDATA[functional-programming]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[typescript]]></category>
            <category><![CDATA[programming]]></category>
            <dc:creator><![CDATA[Federico Kereki]]></dc:creator>
            <pubDate>Tue, 21 Nov 2023 10:58:38 GMT</pubDate>
            <atom:updated>2025-06-28T23:16:31.103Z</atom:updated>
            <content:encoded><![CDATA[<h3>Forever Functional #33 — Complex Typing in TypeScript, Part 2</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*d3MswjMVrufC2OhL9s123w.png" /></figure><blockquote>Adding types to some functional programming constructs may not be simple, and this article will show you different ways of providing data typing for currying higher-order functions.</blockquote><p>In the <a href="https://medium.com/stackanatomy/forever-functional-27-complex-typing-in-typescript-b458f0772880">previous article</a> we saw how to work out a TypeScript version of our <a href="https://medium.com/stackanatomy/forever-functional-26-simpler-code-through-partial-application-b4a6c8dc273c">partial application</a> code. This proved to be feasible but a bit tricky! In this second part, let’s turn our attention to another functional programming tool, <a href="https://medium.com/stackanatomy/forever-functional-16-many-flavors-of-currying-e87d6ee198ac">currying</a>, and see how to develop a fully typed TypeScript version.</p><p>Just to help you remember, currying transforms a function with several parameters into a new function that receives the first argument and returns a function that receives the second argument, which in turn returns a final function accepting the last, third argument and producing the result. (For the reasons and advantages of doing this, refer to the <a href="https://medium.com/stackanatomy/forever-functional-16-many-flavors-of-currying-e87d6ee198ac">previous article</a>.) The following image from my <a href="https://www.amazon.com/Mastering-JavaScript-Functional-Programming-maintainable/dp/1804610135/"><em>Mastering JavaScript Functional Programming</em></a> book, shows the concept.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/619/0*RNCX4rnCKQ5KpiWJ.png" /></figure><p>For an example (taken from the book) we could have:</p><pre>const make3 = (a: string, b: number, c: string): string =&gt; `${a}:${b}:${c}`;<br><br>const f1 = curry(make3);<br>// (arg: string) =&gt; (arg: number) =&gt; (arg: string) =&gt; string<br><br>const f2 = f1(&quot;A&quot;);<br>// (arg: number) =&gt; (arg: string) =&gt; string<br><br>const f3 = f2(2);<br>// (arg: string) =&gt; string<br><br>const f4 = f3(&quot;Z&quot;);<br>// string -- f4 equals &quot;A:2:Z&quot;</pre><p>The make3() function receives three arguments and produces a string. When curried, you get a f1() function that receives the first argument and returns a function, f2(), that receives the second argument and returns a final f3() function, that receives the last argument and returns the value that make3() would have returned.</p><p>The JavaScript code to implement a currying higher-order function was as follows:</p><pre>const curry = (fn) =&gt;<br>  fn.length === 0 ? fn() : (p) =&gt; curry(fn.bind(null, p));</pre><p>The function is recursive, and that’s a challenge for typing. Let’s see how to do that, but first we’ll go with a simplified version.</p><h3>Checking types — the simple version</h3><p>If we knew that we’d never curry functions with, say, more than four parameters, we could make do with a simple, though longish solution.</p><pre>type SimpleCurry&lt;P extends any[], R&gt; = 0 extends P[&quot;length&quot;]<br>  ? R<br>  : EQUALS&lt;1, P[&quot;length&quot;]&gt; extends true<br>  ? (a: P[0]) =&gt; SimpleCurry&lt;[], R&gt;<br>  : EQUALS&lt;2, P[&quot;length&quot;]&gt; extends true<br>  ? (a: P[0]) =&gt; SimpleCurry&lt;[P[1]], R&gt;<br>  : EQUALS&lt;3, P[&quot;length&quot;]&gt; extends true<br>  ? (a: P[0]) =&gt; SimpleCurry&lt;[P[1], P[2]], R&gt;<br>  : EQUALS&lt;4, P[&quot;length&quot;]&gt; extends true<br>  ? (a: P[0]) =&gt; SimpleCurry&lt;[P[1], P[2], P[3]], R&gt;<br>  : never;</pre><p>In this type definition, P represents the array of types for the parameters of the function we are currying, and R represents the result type for that function.</p><ul><li>When the function has no parameters, we return R. This is correct because in our curry() function, if fn.length is zero, we call fn() and return the produced value.</li><li>if the function has one parameter, we return a curried function with no parameters</li><li>if the function has two parameters, we return a curried function with just one parameter.</li><li>if the function has three parameters, we return a curried function with two parameters.</li><li>if the function has four parameters, we return a curried function with three parameters.</li><li>if the function has five or more parameters, we return never indicating an error.</li></ul><p>This is fairly straightforward, and we can now write the following, which works perfectly well. Note I changed from an arrow function to a classic definition; we’ll see why, below.</p><pre>function curry&lt;P extends any[], R&gt;(<br>  fn: (...args: P) =&gt; R<br>): SimpleCurry&lt;P, R&gt;;<br><br>function curry(<br>  fn: (...args: any[]) =&gt; any<br>): SimpleCurry&lt;Parameters&lt;typeof fn&gt;, ReturnType&lt;typeof fn&gt;&gt; {<br>  return fn.length === 0<br>    ? fn()<br>    : (x: any) =&gt; curry(fn.bind(null, x));<br>}</pre><p>You may wonder why we have <em>two</em> definitions for the function. TypeScript cannot verify that our curry() function works correctly because it cannot deduce that, for every function, it will eventually produce a result instead of another curried function. We used a trick in the previous article, which serves well here. We are defining an overloaded function, but with just <em>one</em> signature, which loosens things up for TypeScript. (By the way, it <em>is</em> possible to define overloading for arrow functions, but I think it&#39;s clearer how I did it.) Obviously, this isn&#39;t a very safe way of working; you have to ensure on your own that the function is type-correct because this trick essentially bypasses some of TypeScript&#39;s checks!</p><p>So, our limited version works well, but let’s aim for a version that works with any number of parameters.</p><h3>Checking types — the full version</h3><p>Since the currying function is recursive, we must work recursively. There are two cases that we must consider:</p><ul><li>if we curry an unary function (that is, with a single parameter) the result will be the function itself</li><li>if we carry a function with two or more parameters, the output will be a unary function (with the first parameter) that will return a (curried) function that will deal with the rest of the parameters.</li></ul><p>We can write this the following way:</p><pre>type FullCurry&lt;P, R&gt; = P extends []<br>  ? R<br>  : P extends [infer H]<br>  ? (arg: H) =&gt; R // only 1 arg<br>  : P extends [infer H, ...infer T] // 2 or more args<br>  ? (arg: H) =&gt; FullCurry&lt;[...T], R&gt;<br>  : never;</pre><p>Let’s analyze the code. Again, P is the array of function parameters types, and R is its result type.</p><ul><li>with no parameters, the type is R</li><li>with a single parameter of type H, the result of currying is a function that gets an H-type argument and produces an R-type result</li><li>with more parameters (H and the rest, which we collectively call T - &quot;H&quot; and &quot;T&quot; stand for &quot;Head&quot; and &quot;Tail&quot;, as usual when working with lists) the result of currying is a function that gets an H-type argument and produces a curried function with T-type parameters that eventually returns an R-type result</li></ul><p>The full TypeScript code is essentially the same, only using the new FullCurry type instead.</p><pre>function curry&lt;P extends any[], R&gt;(<br>  fn: (...args: P) =&gt; R<br>): FullCurry&lt;P, R&gt;;<br><br>function curry(fn: (...args: any) =&gt; any) {<br>  return fn.length === 0<br>    ? fn()<br>    : (x: any) =&gt; curry(fn.bind(null, x));<br>}</pre><p>We’ve done it! This recursive type definition can deal with any number of parameters, so we have a general solution. However, remember a restriction: currying only works with functions that have a known, fixed number of parameters, and our code won’t work with other functions.</p><h3>Summary</h3><p>We’ve shown how complex typing also applies to currying, and we have to use an overloading trick to achieve this. Currying is an essential functional programming technique, and in this article, we’ve seen how to use it with TypeScript for better, safer coding; it’s a win!</p><p><em>If you want to read about programming (including functional programming, of course), algorithms in general, and data structures and their applications, take a look at my </em><a href="https://www.amazon.com/Structures-Algorithms-JavaScript-Federico-Kereki/dp/1718502621/ref=sr_1_3"><em>DATA STRUCTURES AND ALGORITHMS IN JAVASCRIPT</em></a><em> and </em><a href="https://www.amazon.com/Mastering-JavaScript-Functional-Programming-maintainable/dp/1804610135/ref=sr_1_5"><em>MASTERING JAVASCRIPT FUNCTIONAL PROGRAMMING</em></a><em> books.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/779/1*NOWSsSbVG71zNQb5QXbn8Q.png" /></figure><p><em>Originally published at </em><a href="https://blog.openreplay.com/forever-functional-complex-typing-in-typescript-part-2/"><em>https://blog.openreplay.com</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ad5bdb274d6e" width="1" height="1" alt=""><hr><p><a href="https://medium.com/stackanatomy/forever-functional-complex-typing-in-typescript-part-2-ad5bdb274d6e">Forever Functional #33 — Complex Typing in TypeScript, Part 2</a> was originally published in <a href="https://medium.com/stackanatomy">StackAnatomy</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Optimize Vue With Web Workers]]></title>
            <link>https://medium.com/stackanatomy/optimize-vue-with-web-workers-263eb28b696f?source=rss----48c8bfd9e724---4</link>
            <guid isPermaLink="false">https://medium.com/p/263eb28b696f</guid>
            <category><![CDATA[vuejs]]></category>
            <dc:creator><![CDATA[AndaMary]]></dc:creator>
            <pubDate>Wed, 25 Oct 2023 00:16:19 GMT</pubDate>
            <atom:updated>2023-10-25T00:16:19.403Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*_d65U8gABP8dQxl0.png" /></figure><blockquote><a href="https://en.wikipedia.org/wiki/Web_worker">Web workers</a> are a modern web technology that provides a way to run JavaScript in the background, parallel to the main execution thread. This concurrency model is especially beneficial in the browser environment, where, traditionally, JavaScript runs in a single-threaded fashion. They enable web applications to run background scripts without interfering with the main thread, and this article will show you how to use them.</blockquote><p><a href="https://vuejs.org/">Vue.js</a> is a progressive JavaScript framework used for building user interfaces, especially single-page applications (SPAs). It is renowned for its simplicity and component-based architecture. Since its introduction, it has evolved as one of the leading JavaScript frameworks, primarily because:</p><ul><li><strong>Reactivity:</strong> Vue’s reactive data-binding system lets developers synchronize the UI with the underlying data model effortlessly.</li><li><strong>Component-based:</strong> This architecture facilitates code reusability and modular development.</li><li><strong>Lightweight:</strong> Vue is incrementally adoptable, meaning developers can start small and scale with complexity as needed.</li></ul><p>Developers cherish Vue because it is easy to integrate and facilitates the creation of powerful single-page applications (SPAs) and user interfaces.</p><p>In today’s web, where applications are becoming increasingly dynamic and data-driven, performance is no longer a luxury-it’s a necessity. Users expect snappy responses, fluid animations, and instantaneous feedback. Here’s where web workers come in:</p><ul><li><strong>Non-blocking Operations:</strong> Web workers can perform tasks without interfering with the main thread. This means the user interface remains entirely responsive while a web worker can process data or perform computations. Heavy computations or processing can hinder a web application’s responsiveness. Web workers mitigate this by running tasks in parallel, ensuring the main thread remains unblocked.</li><li><strong>Optimal CPU Utilization:</strong> On multi-core processors common in today’s devices, web workers can truly shine by leveraging parallel processing capabilities.</li><li><strong>Scalable Web Applications:</strong> As web applications grow and take on more complex tasks, web workers provide a means to manage this complexity without sacrificing performance. They are, in essence, a step forward in building scalable, high-performance web applications.</li></ul><h3>Understanding Web Workers</h3><p>To understand the significance of Web Workers, it is crucial first to comprehend the environment in which JavaScript traditionally operates. JavaScript, by design, is a single-threaded language. This means it has one call stack and one memory heap, executing one operation at a time.<br> While this single-threaded nature simplifies state management and ensures consistency in operation, it can also introduce challenges, particularly with performance. For instance, long-running or computationally intensive tasks can block the main thread, leading to an unresponsive user interface, an issue often termed the “JavaScript freeze”.</p><p>The traditional solution to this issue involved techniques such as asynchronous callbacks, promises, or, more recently, async/await. However, while these solutions provide a way to work around the blocking issue, they don’t solve it entirely — the code is still technically running on the same single thread.</p><p>This is where Web Workers come into play. A web worker is a script the browser runs in the background, separate from the main execution thread. This means that no matter how intensive the operations a worker performs, it won’t block the user interface or other user-triggered scripts.</p><p>A web worker is, in essence, a JavaScript file hosted on a server, created using the Web Worker API’s Worker() constructor. Once instantiated, the worker operates in its own execution environment parallel to the main thread.</p><p>Each web worker has its own JavaScript context and global scope. It doesn’t share any state with the main thread, which helps ensure data consistency and eliminates the risk of race conditions, a common issue in multi-threaded environments.</p><p>Running tasks in the main thread versus a web worker has distinct advantages and drawbacks.</p><ul><li><strong>Main Thread:</strong> When tasks run on the main thread, they can access the page’s DOM and directly manipulate it. They can also use window methods and objects. However, long-running or complex tasks can block user interactions, leading to a “frozen” or laggy interface.</li><li><strong>Web Worker:</strong> Tasks running inside a web worker do not block the main thread, ensuring a smooth, responsive user interface, even when heavy computation occurs in the background. However, web workers cannot access the DOM, limiting their use to non-UI tasks. Furthermore, they require a message-passing mechanism for communication with the main thread, which can be slightly more complex to manage.</li></ul><p>Despite their limitations, web workers represent a significant step forward in JavaScript’s journey towards efficient multithreading and parallel processing capabilities, opening up new possibilities for performance optimization in web applications.</p><h3>Integrating Web Workers in Vue.js</h3><p>Before you start, identify the tasks in your application causing the UI to become unresponsive or are computationally heavy. These are prime candidates to be moved into a Web Worker.</p><p>One situation where Web Workers excel is in the realm of image processing. For example, when it comes to blurring an image, each pixel must be adjusted based on its neighboring pixels. This task can be computationally demanding for images. This may lead to unresponsive user interfaces if performed on the main thread.</p><p>Why Choose a Web Worker for Image Blurring? Three reasons come to mind:</p><ul><li><strong>Enhanced Responsiveness</strong>: Blurring an high-resolution image can take time. If done on the thread, it can temporarily freeze the application and hinder user interactions. The main thread remains available by delegating this task to a web worker. Ensures that the application remains responsive.</li><li><strong>Improved Performance</strong>: Parallel processing can significantly boost image processing capabilities. On devices with cores, leveraging a web worker allows for processing by utilizing these cores effectively.</li><li><strong>Separation of Concerns</strong>: Image processing algorithms can be intricate and involved. We maintain focused application logic that prioritizes UI-related tasks by isolating this functionality within a web worker.</li></ul><p>The following sections will illustrate how to create a Vue application that utilizes a Web Worker for blurring images. Users can upload images and instantly view the version within the application without experiencing any noticeable lag or delay. This is a feature that truly highlights the capabilities and efficiency of Web Workers in real-world usage scenarios.</p><h3>Create the Worker File</h3><p>Web Workers run in a separate file. Let’s create a new file called imageBlurWorker.js.</p><p>In imageBlurWorker.js, you can add your computation-intensive code:</p><pre>self.onmessage = function (e) {<br> const imageData = e.data;<br> const blurredData = applyBoxBlur(imageData);<br> postMessage(blurredData);<br>};<br><br>function applyBoxBlur(imageData) {<br> // Your image blurring logic here.<br> // E.g;<br> const width = imageData.width;<br> const height = imageData.height;<br> const data = new Uint8ClampedArray(imageData.data);<br><br> const outputData = new Uint8ClampedArray(data.length);<br><br> for (let y = 0; y &lt; height; y++) {<br>   for (let x = 0; x &lt; width; x++) {<br>     const pixelIndex = y * width * 4 + x * 4;<br>     const redSum = [0, 0, 0];<br>     const pixelCount = 9;<br><br>     for (let dy = -1; dy &lt;= 1; dy++) {<br>       for (let dx = -1; dx &lt;= 1; dx++) {<br>         const neighborY = y + dy;<br>         const neighborX = x + dx;<br><br>         if (<br>           neighborY &gt;= 0 &amp;&amp;<br>           neighborY &lt; height &amp;&amp;<br>           neighborX &gt;= 0 &amp;&amp;<br>           neighborX &lt; width<br>         ) {<br>           const neighborIndex = neighborY * width * 4 + neighborX * 4;<br>           redSum[0] += data[neighborIndex];<br>           redSum[1] += data[neighborIndex + 1];<br>           redSum[2] += data[neighborIndex + 2];<br>         }<br>       }<br>     }<br><br>     const outputIndex = y * width * 4 + x * 4;<br>     outputData[outputIndex] = redSum[0] / pixelCount;<br>     outputData[outputIndex + 1] = redSum[1] / pixelCount;<br>     outputData[outputIndex + 2] = redSum[2] / pixelCount;<br>     outputData[outputIndex + 3] = data[pixelIndex + 3]; // Alpha channel<br>   }<br> }<br><br> return {<br>   width: width,<br>   height: height,<br>   data: outputData,<br> };<br>}</pre><p>In the applyBoxBlur function, we implemented a basic box blur algorithm, a type of neighborhood averaging. The idea is to replace each pixel&#39;s color value with the average of its neighboring pixels, including itself.</p><p>Here’s a step-by-step breakdown:</p><pre>function applyBoxBlur(imageData) {<br> // 1 Extract the width, height, and data from the image<br> const width = imageData.width;<br> const height = imageData.height;<br> const data = new Uint8ClampedArray(imageData.data);<br> const outputData = new Uint8ClampedArray(data.length);<br><br> // 2 Iterate over each pixel in the image<br> for (let y = 0; y &lt; height; y++) {<br>   for (let x = 0; x &lt; width; x++) {<br>     const pixelIndex = y * width * 4 + x * 4;<br>     let redSum = 0,<br>       greenSum = 0,<br>       blueSum = 0;<br>     let pixelCount = 0;<br><br>     // 3 For each pixel, look at its immediate neighbors (the 3x3 grid around the pixel)<br>     for (let dy = -1; dy &lt;= 1; dy++) {<br>       for (let dx = -1; dx &lt;= 1; dx++) {<br>         const neighborY = y + dy;<br>         const neighborX = x + dx;<br><br>         // 4 Check boundaries to ensure we don&#39;t access pixels outside the image<br>         if (<br>           neighborY &gt;= 0 &amp;&amp;<br>           neighborY &lt; height &amp;&amp;<br>           neighborX &gt;= 0 &amp;&amp;<br>           neighborX &lt; width<br>         ) {<br>           const neighborIndex = neighborY * width * 4 + neighborX * 4;<br>           redSum += data[neighborIndex];<br>           greenSum += data[neighborIndex + 1];<br>           blueSum += data[neighborIndex + 2];<br>           pixelCount++;<br>         }<br>       }<br>     }<br><br>     // 5 Compute the average color value<br>     outputData[pixelIndex] = redSum / pixelCount;<br>     outputData[pixelIndex + 1] = greenSum / pixelCount;<br>     outputData[pixelIndex + 2] = blueSum / pixelCount;<br>     outputData[pixelIndex + 3] = data[pixelIndex + 3]; // Alpha channel (transparency) remains unchanged<br>   }<br> }<br><br> // Return the new image data (blurred version)<br> return {<br>   width: width,<br>   height: height,<br>   data: outputData,<br> };<br>}</pre><ol><li><strong>Initialization</strong>: We extract the image’s dimensions and data. We extract the width and height of the image. The Uint8ClampedArray is a typed array that clamps the values between 0 and 255, which is perfect for our RGBA values</li><li><strong>Iterate Over Pixels</strong>: For each pixel in the image, we determine the average color value of its neighbors.</li><li><strong>Determine Neighbors</strong>: We look at each pixel’s immediate neighbors (the 3x3 grid around the pixel).</li><li><strong>Sum Color Values</strong>: pixelIndex determines the index in the data array for the current pixel.redSum is then initialized to store the summed values for red, green, and blue channels, respectively, and we iterate over the neighboring pixels using the nested loops. For each neighbor, we calculate its position in the data array using neighborIndex. We then add the neighbor&#39;s red, green, and blue values to our redSum array.</li><li><strong>Calculate Averages</strong>: outputIndex determines the position of the current pixel in the output data array. We then divide the summed values for each channel by pixelCount (9, representing the 3x3 grid) to get the average. These averaged values are then stored in the outputData array.</li></ol><p>The box blur is a simple and effective method for image blurring, but it’s worth noting that other, more advanced blurring techniques are available. The box blur provides a uniform blur, but other methods can provide more nuanced or directional blurs, depending on the desired effect.</p><h3>Instantiate and Use the Worker in Your Main Application</h3><p>In your main JavaScript file or within a specific module where you need to use the worker:</p><pre>// Initialize the worker<br>const worker = new Worker(&quot;imageBlurWorker.js&quot;);<br><br>// Set up an event listener to receive messages from the worker<br>worker.onmessage = function (event) {<br> const result = event.data;<br> console.log(&quot;Received result from worker:&quot;, result);<br>};<br><br>// Send data to the worker<br>const someData = { /.../ };<br>worker.postMessage(someData);<br><br>// Remember to terminate the worker when you&#39;re done<br>// worker.terminate();</pre><h3>Implement a web worker into Vue to create an image blur app</h3><p>For example, Let us incorporate the web worker into a Vue component.</p><p>In your Vue component, you can instantiate a worker using the Worker constructor, passing the path to your worker script as an argument:</p><pre>const worker = new Worker(&#39;./imageBlurWorker.js&#39;);</pre><h4>Post messages to the worker and listen for its response.</h4><p>To send data to the worker, use the postMessage method:</p><pre>self.postMessage(blurredData);</pre><p>To listen for messages from the worker, assign a function to the onmessage event handler of the worker:</p><pre>self.onmessage = function (e) {<br> const imageData = e.data;<br> const blurredData = applyBoxBlur(imageData);<br>};</pre><h4>Demonstration in a Vue component</h4><p>Here’s how you might use the Image blur worker within a Vue component:</p><pre>&lt;template&gt;<br> &lt;div&gt;<br>   &lt;input type=&quot;file&quot; accept=&quot;image/*&quot; @change=&quot;handleImageUpload&quot; /&gt;<br>   &lt;div v-if=&quot;blurredImage&quot;&gt;<br>     &lt;img :src=&quot;blurredImage&quot; alt=&quot;Blurred Image&quot; /&gt;<br>   &lt;/div&gt;<br> &lt;/div&gt;<br>&lt;/template&gt;<br><br>&lt;script&gt;<br>export default {<br> data() {<br>   return {<br>     imageBlurWorker: null,<br>     blurredImage: null,<br>   };<br> },<br> created() {<br>   this.imageBlurWorker = new Worker(&quot;imageBlurWorker.js&quot;);<br><br>   this.imageBlurWorker.onmessage = (e) =&gt; {<br>     const blurredImageData = e.data;<br>     const canvas = document.createElement(&quot;canvas&quot;);<br>     const ctx = canvas.getContext(&quot;2d&quot;);<br>     canvas.width = blurredImageData.width;<br>     canvas.height = blurredImageData.height;<br>     ctx.putImageData(<br>       new ImageData(<br>         blurredImageData.data,<br>         blurredImageData.width,<br>         blurredImageData.height,<br>       ),<br>       0,<br>       0,<br>     );<br>     const blurredImageURL = canvas.toDataURL();<br>     this.blurredImage = blurredImageURL;<br>   };<br><br>   this.imageBlurWorker.onerror = (error) =&gt; {<br>     console.error(`Worker error: ${error.message}`);<br>   };<br> },<br> methods: {<br>   handleImageUpload(event) {<br>     const file = event.target.files[0];<br>     if (file) {<br>       const reader = new FileReader();<br>       reader.onload = (e) =&gt; {<br>         const arrayBuffer = e.target.result;<br>         const blob = new Blob([arrayBuffer], { type: file.type });<br>         const img = new Image();<br>         img.onload = () =&gt; {<br>           const canvas = document.createElement(&quot;canvas&quot;);<br>           const ctx = canvas.getContext(&quot;2d&quot;);<br>           canvas.width = img.width;<br>           canvas.height = img.height;<br>           ctx.drawImage(img, 0, 0);<br>           const imageData = ctx.getImageData(0, 0, img.width, img.height);<br>           this.imageBlurWorker.postMessage(imageData);<br>         };<br>         img.src = URL.createObjectURL(blob);<br>       };<br>       reader.readAsArrayBuffer(file);<br>     }<br>   },<br> },<br> beforeDestroy() {<br>   this.imageBlurWorker.terminate();<br> },<br>};<br>&lt;/script&gt;</pre><p>Image before blurring:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/0*XM-q3dSrYE697TL4.png" /></figure><p>Output of result of blurred image:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/0*mTWrFinPzkPyDzFJ.png" /></figure><h4>Clean up and terminate the worker</h4><p>When the component is destroyed, or when you no longer need the worker, you should terminate it to free up resources:</p><pre>worker.terminate();</pre><p>This should be done in the beforeDestroy lifecycle hook in Vue to ensure it happens when the component is destroyed.</p><p>Following this guide, you can offload intensive computations to a separate thread in your Vue.js applications, resulting in smoother, more responsive user interfaces.</p><h3>Benefits of Using Web Workers in Vue.js</h3><p>There are several benefits to using web workers.</p><h4>Enhanced Performance and Scalability</h4><p>When you delegate computational tasks to a Web Worker, the main thread remains free to handle other critical tasks. As a result, your application can accommodate more concurrent operations and scale more effectively, leading to a noticeable performance boost.</p><p>To illustrate, if your application includes complex data processing tasks or sophisticated algorithms that can create a noticeable delay, you can offload these tasks to a Web Worker. This approach ensures that these time-consuming tasks won’t block the main thread, leading to a more responsive application.</p><h4>Improved User Experience</h4><p>With Web Workers, the user interface remains highly responsive, leading to a better user experience. This is because the main thread, responsible for user interactions and UI rendering, remains unblocked and can immediately respond to user actions. Therefore, users won’t experience a frozen or unresponsive interface, even during heavy computations.</p><h4>Asynchronous Operations</h4><p>Web Workers thrive in handling tasks that are asynchronous or involve operations like fetching data, working with indexedDB, or crunching large datasets. They can handle such operations independently, sending the results back when ready. This allows Vue.js to continue executing other tasks, including updating the DOM and responding to user events.</p><p>Ultimately, using Web Workers in Vue.js provides considerable performance benefits, improves user experience, and allows for more efficient use of modern hardware. It represents a significant evolution in how we can build complex and highly responsive web applications.</p><h3>Drawbacks and Limitations of Web Workers</h3><p>Of course, there are some drawbacks as well.</p><h4>Lack of DOM Access</h4><p>Web Workers operate on their own thread and cannot access the DOM. This limitation stems from the potential conflicts that could arise from having multiple threads interact with the DOM simultaneously. While this design helps ensure thread safety, any DOM manipulation must happen on the main thread. For instance, you can’t manipulate Vue components directly from a Web Worker or use Vue’s reactivity system within a worker. This means you’ll have to send messages back to the main thread when you want to update the UI based on a computation done by the worker.</p><h4>Limited Access to Web APIs</h4><p>Web Workers don’t have access to all Web APIs that the main thread does. Besides the DOM, they can’t access APIs such as localStorage or the methods provided by window object. This limits the tasks that can be offloaded to a Web Worker.</p><h4>Complexity of Multithreading</h4><p>While Web Workers offer the advantage of concurrent execution, they also introduce the complexities of multi-threaded programming into the web environment. Developers need to manage the synchronization between the main and every worker thread, handle potential race conditions, and deal with error handling in a distributed environment. Debugging can also be more challenging with Web Workers due to their isolated execution context.</p><p>While Web Workers can greatly improve the performance of a Vue.js application, these advantages come with their own challenges. A careful assessment of the tasks to be offloaded, the data to be processed, and the necessary synchronization can help you navigate these limitations and make the most out of Web Workers.</p><h3>Conclusion</h3><p>In this article, we explored Web Workers and their integration within Vue.js. We covered the intricacies of how JavaScript and Web Workers operate, showcasing a practical implementation of a Web Worker in a Vue.js component. In examining the benefits, we highlighted the potential performance enhancements and improved user experience. Despite acknowledging their limitations, including lack of DOM access and communication overhead, we concluded that the effective use of Web Workers can significantly improve the efficiency and interactivity of Vue.js applications.</p><p><em>Originally published at </em><a href="https://dev.to/asayerio_techblog/optimize-vue-with-web-workers-5295"><em>https://dev.to</em></a><em> on October 13, 2023.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=263eb28b696f" width="1" height="1" alt=""><hr><p><a href="https://medium.com/stackanatomy/optimize-vue-with-web-workers-263eb28b696f">Optimize Vue With Web Workers</a> was originally published in <a href="https://medium.com/stackanatomy">StackAnatomy</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Build A ChatBot With ChatGPT And React]]></title>
            <link>https://medium.com/stackanatomy/build-a-chatbot-with-chatgpt-and-react-5db10b50da78?source=rss----48c8bfd9e724---4</link>
            <guid isPermaLink="false">https://medium.com/p/5db10b50da78</guid>
            <category><![CDATA[chatbots]]></category>
            <category><![CDATA[chatbot-development]]></category>
            <category><![CDATA[chatgpt]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[react]]></category>
            <dc:creator><![CDATA[Onu Daniel Onyebuchi]]></dc:creator>
            <pubDate>Wed, 25 Oct 2023 00:15:29 GMT</pubDate>
            <atom:updated>2023-10-25T00:15:29.239Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*I_3_-1qf3HMUzRtm2Hh7ZA.png" /></figure><blockquote>As AI technology advances, chatbots have become a powerful tool for improving user interactions. By combining ChatGPT with user-friendly frameworks like React, developers can create intelligent and dynamic chatbots that engage users in natural and meaningful conversations. This article will show you how to create an AI chatbot using ChatGPT and React, setting up the development environment, customizing the chatbot’s user interface, and managing responses from the ChatGPT API.</blockquote><p>Let’s start with the setup. This involves importing dependencies and installing the tools and software the app will need.</p><p>Some tools and software that we will use to build the simple chatbot are:</p><ol><li><strong>Node.js and npm:</strong> Install Node.js, which includes npm (Node Package Manager), from the official <a href="https://nodejs.org/">website</a>. npm will be used to manage dependencies and run scripts for the project.</li><li><strong>Create a new React App using Vite:</strong> Open your terminal and create a new React app by running the command below</li></ol><pre>npm create vite@latest app -- --template react</pre><p>Navigate to the app directory using this command in your terminal:</p><pre>cd app</pre><p>Then, run:</p><pre>npm install</pre><ol><li><strong>Install </strong><strong>chat-ui-kit-react:</strong> This is a UI kit library for building chat interfaces in React applications. To install it, use the following command:</li></ol><pre>npm install @chatscope/chat-ui-kit-react</pre><p>To learn more about the chat-ui-kit-react library, you can read the documentation <a href="https://chatscope.io/storybook/react/">here</a></p><p>We’ll also require some dependencies that will be used in styling the components. The dependencies will be imported on the App.jsx file. You can find it by</p><ul><li>Expanding the app folder.</li><li>Clicking on the src folder.</li><li>Navigating to App.jsx.</li><li>On App.jsx, delete the template and leave only the parent element. This is what the App.jsx file should look like.</li></ul><pre>import { useState } from &#39;react&#39;<br>import reactLogo from &#39;./assets/react.svg&#39;<br>import viteLogo from &#39;/vite.svg&#39;<br>import &#39;./App.css&#39;<br><br>function App() {<br> return (<br>   &lt;&gt;      <br>   &lt;/&gt;<br> )<br>}<br>export default App</pre><p>Import the following components:</p><pre>import &#39;@chatscope/chat-ui-kit-styles/dist/default/styles.min.css&#39;;<br>import { MainContainer, ChatContainer, MessageList, Message, MessageInput, TypingIndicator } from &#39;@chatscope/chat-ui-kit-react&#39;</pre><h3>Creating Chat UI</h3><p>chat-ui-kit-react provides components to create a chat interface. We will build the components that include all our chat functionalities in our App.jsx file.</p><pre>return (<br> &lt;&gt;<br>   {/* A container for the chat window */}<br>   &lt;div style={{ position: &quot;relative&quot;, height: &quot;100vh&quot;, width: &quot;700px&quot; }}&gt;<br>     {/* All components are wrapped in the MainContainer */}<br>     &lt;MainContainer&gt;<br>       {/* All chat logic will be contained in the ChatContainer */}<br>       &lt;ChatContainer&gt;<br>         {/* Shows all our messages */}<br>         &lt;MessageList&gt;&lt;/MessageList&gt;<br>       &lt;/ChatContainer&gt;<br>     &lt;/MainContainer&gt;<br>   &lt;/div&gt;<br> &lt;/&gt;<br>);</pre><p>Further styling can be applied by editing the Index.css file or adding inline styles.</p><h3>Manage Messages State</h3><p>The MessageList component is used to display all of our various messages. We need to store these messages in an array using useState and initialize it with one message.</p><pre>// State to store chat messages<br>const [chatMessages, setChatMessages] = useState([<br> {<br>   message: &quot;Hello, I am ChatGPT!&quot;,<br>   sender: &quot;ChatGPT&quot;,<br> },<br>]);</pre><p>To display these messages in our UI, we can achieve this by mapping over the array and rendering each message.</p><pre>&lt;MessageList&gt;<br> {/* Map through chat messages and render each message */}<br> {chatMessages.map((message, i) =&gt; {<br>   return &lt;Message key={i} model={message} /&gt;;<br> })}<br>&lt;/MessageList&gt;;</pre><p>For a better layout, we can apply some styling to messages from ChatGPT so that the responses are aligned to the left.</p><pre>&lt;MessageList&gt;<br> {/* Map through chat messages and render each message */}<br> {chatMessages.map((message, i) =&gt; {<br>   return (<br>     &lt;Message<br>       key={i}<br>       model={message}<br>       style={message.sender === &quot;ChatGPT&quot; ? { textAlign: &quot;left&quot; } : {}}<br>     /&gt;<br>   );<br> })}<br>&lt;/MessageList&gt;;</pre><p>We can view our Chatbot by running this command on the terminal.</p><pre>npm run dev</pre><p>Our UI should look like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*te_UnZaoXifmPW53.png" /></figure><h3>Handling user input</h3><p>MessageInput component enables users to input messages for processing. Additionally, we can implement a function named handleUserMessage to manage the user’s entered messages. This component should be added after the MessageList component.</p><pre>&lt;MessageInput placeholder=&#39;Type Message here&#39; onSend={handleUserMessage}/&gt;</pre><p>Now, let’s create the handleUserMessage function. This function will serve two roles:</p><ol><li>Creating a new user object that will contain: i. The message from the user. ii. A description of the user as the sender. iii. Indication of the message direction as outgoing. This means the message will be displayed on the left side of the chat UI.</li><li>Updating chat messages with the new user message.</li></ol><pre>// Function to handle user messages<br>const handleUserMessage = async (userMessage) =&gt; {<br> // Create a new user message object<br> const newUserMessage = {<br>   message: userMessage,<br>   sender: &quot;user&quot;,<br>   direction: &quot;outgoing&quot;,<br> }; <br><br>// Update chat messages state with the new user message<br> const updatedChatMessages = [...chatMessages, newUserMessage];<br> setChatMessages(updatedChatMessages);<br>};</pre><h3>Set Up ChatGPT API</h3><p>To set up ChatGPT API to process user messages, we can follow these steps:</p><h3>Obtaining an API key from OpenAI</h3><ul><li>Visit the <a href="https://platform.openai.com/">OpenAI website</a> and create an account.</li><li>Log in to your account and click on your profile name or icon to access the menu.</li><li>From the menu, select the ‘View API Keys’ option.</li><li>Click on the ‘Create New Secret Key’ button.</li><li>Once the API key is generated, copy and paste it somewhere safe. <strong>Note:</strong> The key will not be displayed again, so store it securely.</li></ul><h3>Setting up ChatGPT API access</h3><p>We can store the API key as a variable above the App function.</p><pre>const OPENAI_API_KEY = &quot;YOUR API KEY&quot;; //Replace with your generated openai api key</pre><h3>Process Message with ChatGPT API</h3><p>After the handleUserMessage function, we will create an asynchronous function called processUserMessageToChatGPT. This function captures the user’s message, sends it to ChatGPT, and returns a response from ChatGPT. The steps involved are as follows:</p><p><strong>Preparing the messages in the required format for the API</strong>: Messages are categorized into three roles: User, Assistant, and System. “User” represents messages input by the user, and “Assistant” refers to messages from ChatGPT.</p><pre>async function processUserMessageToChatGPT(messages) {<br> // Prepare the messages in the required format for the API<br> let apiMessages = messages.map((messageObject) =&gt; {<br>   let role = &quot;&quot;;<br>   if (messageObject.sender === &quot;ChatGPT&quot;) {<br>     role = &quot;assistant&quot;;<br>   } else {<br>     role = &quot;user&quot;;<br>   }<br>   return { role: role, content: messageObject.message };<br> });<br>}</pre><p><strong>Create a System message for ChatGPT:</strong> A system message is a special message that provides instructions or context to the language model before processing user messages. It helps guide the behavior and response of the model during the conversation. For instance, a system message could include instructions like:</p><ul><li>“Explain all concepts like Shakespeare.”</li><li>“You are a customer support representative for a tech company.” You can improve the system message prompt for specific chatbot use cases across different industries, such as Travel, Technology, etc.</li></ul><pre>// System message for ChatGPT<br>const systemMessage = {<br> role: &quot;system&quot;,<br> content: &quot;Explain all concept like a Professor in Biochemistry&quot;,<br>};</pre><p><strong>Prepare the API request body:</strong> This is used as a container for the conversation messages and system instructions, and it is sent to the OpenAI API for processing by the ChatGPT model.</p><pre>const apiRequestBody = {<br> model: &quot;gpt-3.5-turbo&quot;,<br> messages: [<br>   systemMessage, // System message should be in front of user messages<br>   ...apiMessages,<br> ],<br>};</pre><p>Send the user message to ChatGPT API and return the response.</p><pre>await fetch(&quot;https://api.openai.com/v1/chat/completions&quot;, {<br> method: &quot;POST&quot;,<br> // Set the request headers, including the authorization, using the API key.<br> headers: {<br>   Authorization: &quot;Bearer &quot; + OPENAI_API_KEY, // Replace OPENAI_API_KEY with the actual API key.<br>   &quot;Content-Type&quot;: &quot;application/json&quot;,<br> },<br> // Convert the API request body object into a JSON string and send it as the request body.<br> body: JSON.stringify(apiRequestBody),<br>})<br> // Once the API response is received, convert it to JSON format.<br> .then((data) =&gt; {<br>   return data.json();<br> })<br> // After converting to JSON, extract the chatbot&#39;s response message from the API response.<br> .then((data) =&gt; {<br>   // Update the chat messages.<br>   setChatMessages([<br>     ...messages,<br>     {<br>       message: data.choices[0].message.content,<br>       sender: &quot;ChatGPT&quot;,<br>     },<br>   ]);<br> });</pre><p><strong>Note:</strong> Remember to include a space after “Bearer” in the Authorization header; otherwise, API calls may fail.</p><p>We can now call the processUserMessageToChatGPT function in the handleUserMessage function.</p><pre>await processUserMessageToChatGPT(updatedChatMessages);</pre><h3>Managing loading states while waiting for the API response</h3><p>We can set a typing indicator to display while the chatbot is processing a response. Firstly, we’ll create a state to indicate typing and set it to false.</p><pre>// State to manage the typing indicator of the chatbot<br>const [isChatbotTyping, setIsChatbotTyping] = useState(false);</pre><p>In the handleUserMessage function, you can set the indicator to true. This line should be added before calling the processUserMessageToChatGPT function.</p><pre>// Set the typing indicator for the chatbot<br>setIsChatbotTyping(true);</pre><p>Once the response has been received from ChatGPT, within the processUserMessageToChatGPT function, you can set the state to false after updating the chat messages.</p><pre>// Set the typing indicator to false after getting the response<br>setIsChatbotTyping(false);</pre><p>You can display the indicator in the UI when it’s true by utilizing the typingIndicator property.</p><pre>&lt;MessageList<br> // Display a typing indicator when the chatbot is processing a response.<br> typingIndicator={<br>   isChatbotTyping ? &lt;TypingIndicator content=&quot;ChatGPT is thinking&quot; /&gt; : null<br> }<br>&gt;<br> {/* Map through chat messages and render each message */}<br> {chatMessages.map((message, i) =&gt; {<br>   return (<br>     // Render each individual chat message as a &lt;Message&gt; component.<br>     &lt;Message<br>       key={i}<br>       model={message}<br>       // Add additional styling to align the chatbot&#39;s response to the left.<br>       style={message.sender === &quot;ChatGPT&quot; ? { textAlign: &quot;left&quot; } : {}}<br>     /&gt;<br>   );<br> })}<br>&lt;/MessageList&gt;;</pre><p>The Final App.jsx file should look like this:</p><pre>import { useState } from &quot;react&quot;;<br>import reactLogo from &quot;./assets/react.svg&quot;;<br>import viteLogo from &quot;/vite.svg&quot;;<br>import &quot;./App.css&quot;;<br>import &quot;@chatscope/chat-ui-kit-styles/dist/default/styles.min.css&quot;;<br>import {<br> MainContainer,<br> ChatContainer,<br> MessageList,<br> Message,<br> MessageInput,<br> TypingIndicator,<br>} from &quot;@chatscope/chat-ui-kit-react&quot;;<br><br>const OPENAI_API_KEY = &quot;YOUR API KEY&quot;;<br><br>function App() {<br> // State to manage the typing indicator of the chatbot<br> const [isChatbotTyping, setIsChatbotTyping] = useState(false);<br><br> // State to store chat messages<br> const [chatMessages, setChatMessages] = useState([<br>   {<br>     message: &quot;Hello, I am ChatGPT!&quot;,<br>     sender: &quot;ChatGPT&quot;,<br>   },<br> ]);<br><br> // Function to handle user messages<br> const handleUserMessage = async (userMessage) =&gt; {<br>   // Create a new user message object<br>   const newUserMessage = {<br>     message: userMessage,<br>     sender: &quot;user&quot;,<br>     direction: &quot;outgoing&quot;,<br>   };<br><br>   // Update chat messages state with the new user message<br>   const updatedChatMessages = [...chatMessages, newUserMessage];<br>   setChatMessages(updatedChatMessages);<br><br>   // Set the typing indicator for the chatbot<br>   setIsChatbotTyping(true);<br><br>   // Process user message with ChatGPT<br>   await processUserMessageToChatGPT(updatedChatMessages);<br> };<br><br> // Function to send the user message to ChatGPT API<br> async function processUserMessageToChatGPT(messages) {<br>   // Prepare the messages in the required format for the API<br>   let apiMessages = messages.map((messageObject) =&gt; {<br>     let role = &quot;&quot;;<br>     if (messageObject.sender === &quot;ChatGPT&quot;) {<br>       role = &quot;assistant&quot;;<br>     } else {<br>       role = &quot;user&quot;;<br>     }<br>     return { role: role, content: messageObject.message };<br>   });<br><br>   // System message for ChatGPT<br>   const systemMessage = {<br>     role: &quot;system&quot;,<br>     content: &quot;Explain all concept like a Professor in Biochemistry&quot;,<br>   };<br><br>   // Prepare the API request body<br>   const apiRequestBody = {<br>     model: &quot;gpt-3.5-turbo&quot;,<br>     messages: [<br>       systemMessage, // System message should be in front of user messages<br>       ...apiMessages,<br>     ],<br>   };<br><br>   // Send the user message to ChatGPT API<br>   await fetch(&quot;https://api.openai.com/v1/chat/completions&quot;, {<br>     method: &quot;POST&quot;,<br>     headers: {<br>       Authorization: &quot;Bearer &quot; + OPENAI_API_KEY,<br>       &quot;Content-Type&quot;: &quot;application/json&quot;,<br>     },<br>     body: JSON.stringify(apiRequestBody),<br>   })<br>     .then((data) =&gt; {<br>       return data.json();<br>     })<br>     .then((data) =&gt; {<br>       // Update chat messages with ChatGPT&#39;s response<br>       setChatMessages([<br>         ...messages,<br>         {<br>           message: data.choices[0].message.content,<br>           sender: &quot;ChatGPT&quot;,<br>         },<br>       ]);<br>       // Set the typing indicator to false after getting the response<br>       setIsChatbotTyping(false);<br>     });<br> }<br><br> return (<br>   &lt;&gt;<br>     {/* A container for the chat window */}<br>     &lt;div style={{ position: &quot;relative&quot;, height: &quot;100vh&quot;, width: &quot;700px&quot; }}&gt;<br>       &lt;MainContainer&gt;<br>         &lt;ChatContainer&gt;<br>           {/* Display chat messages and typing indicator */}<br>           &lt;MessageList<br>             typingIndicator={<br>               isChatbotTyping ? (<br>                 &lt;TypingIndicator content=&quot;ChatGPT is thinking&quot; /&gt;<br>               ) : null<br>             }<br>           &gt;<br>             {/* Map through chat messages and render each message */}<br>             {chatMessages.map((message, i) =&gt; {<br>               return (<br>                 &lt;Message<br>                   key={i}<br>                   model={message}<br>                   style={<br>                     message.sender === &quot;ChatGPT&quot; ? { textAlign: &quot;left&quot; } : {}<br>                   }<br>                 /&gt;<br>               );<br>             })}<br>           &lt;/MessageList&gt;<br>           {/* Input field for the user to type messages */}<br>           &lt;MessageInput<br>             placeholder=&quot;Type Message here&quot;<br>             onSend={handleUserMessage}<br>           /&gt;<br>         &lt;/ChatContainer&gt;<br>       &lt;/MainContainer&gt;<br>     &lt;/div&gt;<br>   &lt;/&gt;<br> );<br>}<br><br>export default App;</pre><p>Your AI ChatBot, with its full functionality, is now complete.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/900/0*P2skOGpaog4ZLawz.gif" /></figure><h3>Common Errors and How to Fix Them</h3><p>Errors may occur during the installation of the chat-ui-kit-react library. You may encounter errors such as:</p><pre>npm ERR! code 1<br>npm ERR! path C:\Users\work\Documents\vs code\app\node_modules\esbuild<br>npm ERR! command failed<br>npm ERR! command C:\Windows\system32\cmd.exe /d /s /c node install.js<br>npm ERR! node:child_process:828<br>npm ERR!     err = new Error(msg);<br>npm ERR!           ^<br>npm ERR!<br>npm ERR! Error: Command failed: C:\Program Files\nodejs\node.exe</pre><p>Here’s how you can resolve it:</p><ul><li>Remove the node modules</li></ul><pre>rmdir /s /q node_modules</pre><ul><li>Install the latest npm</li></ul><pre>npm install -g npm@latest</pre><ul><li>Finally, reinstall the package</li></ul><pre>npm install @chatscope/chat-ui-kit-react</pre><p>Errors may also occur when making requests to the API. This is the <a href="https://platform.openai.com/docs/guides/error-codes/api-errors">documentation</a> on the meaning of the different errors you may encounter.</p><h3>Conclusion</h3><p>Setting up the development environment, Creating the chatbot user interface, and handling user messages using the ChatGPT API are vital steps in building an effective chatbot. With the power of AI, chatbots can significantly enhance user interactions and customer service in various industries.</p><p>So, go ahead and explore the world of AI chatbots with ChatGPT and React, and unlock new possibilities for seamless and interactive user engagements!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5db10b50da78" width="1" height="1" alt=""><hr><p><a href="https://medium.com/stackanatomy/build-a-chatbot-with-chatgpt-and-react-5db10b50da78">Build A ChatBot With ChatGPT And React</a> was originally published in <a href="https://medium.com/stackanatomy">StackAnatomy</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>