<?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[Stories by Brujo Benavides on Medium]]></title>
        <description><![CDATA[Stories by Brujo Benavides on Medium]]></description>
        <link>https://medium.com/@elbrujohalcon?source=rss-788b9596f013------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*k0gUAMy1NUpdsTSdMqDPSA.jpeg</url>
            <title>Stories by Brujo Benavides on Medium</title>
            <link>https://medium.com/@elbrujohalcon?source=rss-788b9596f013------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 16:12:57 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@elbrujohalcon/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Erlang/OTP: Un Mundo Concurrente]]></title>
            <link>https://medium.com/erlang-battleground/erlang-otp-un-mundo-concurrente-a9d86564159d?source=rss-788b9596f013------2</link>
            <guid isPermaLink="false">https://medium.com/p/a9d86564159d</guid>
            <category><![CDATA[books]]></category>
            <category><![CDATA[erlang]]></category>
            <category><![CDATA[spanish]]></category>
            <dc:creator><![CDATA[Brujo Benavides]]></dc:creator>
            <pubDate>Tue, 22 Mar 2022 13:23:49 GMT</pubDate>
            <atom:updated>2022-03-22T13:26:00.909Z</atom:updated>
            <content:encoded><![CDATA[<h4>Mi Reseña</h4><p>Luego de casi quince años de trabajar, enseñar y difundir Erlang por el mundo, recién hace unos pocos días tuve la posibilidad de leer mi primer libro sobre Erlang <strong>en castellano</strong>. Se trata del libro que da título a este artículo y está escrito por <a href="https://medium.com/u/7081b45b4fd3">Manuel Rubio</a>. Aquí van mis opiniones…</p><figure><img alt="Yo, con el libro" src="https://cdn-images-1.medium.com/max/1024/1*KkKnSmTmuwTUYYVTejv3RQ.jpeg" /><figcaption>Sí, el libro en papel me conseguí.</figcaption></figure><h3>En Resumen</h3><p>Para aquellos que no estén interesados en los detalles, comencemos con la conclusión directamente así se pueden saltear las siguientes secciones si no les interesan.</p><p>En general este libro contiene <strong>exactamente</strong> todo lo que yo suelo enseñar en cualquier curso de introducción a Erlang. Y lo mejor que tiene es que está <strong>en castellano</strong>. Así que si tú estás intentando aprender Erlang o si conoces a alguien que está dando sus primeros pasos en este lenguaje/tecnología, éste es definitivamente el libro que debes recomendarle!</p><p>Y ahora, sin un orden particular, pasemos a los detalles…</p><h4>En Castellano</h4><p>Desde mi punto de vista <em>porteño</em>, donde se considera <em>cool</em> usar términos directamente en inglés en lugar de traducirlos, leer un libro en el que a los <em>scripts</em> se les dice <em>guiones</em>, al <em>soft-real-time</em> se le dice <em>tiempo real blando</em> y se incluyen términos como <em>enlace vital</em> y otros es a tanto un desafío mental como una experiencia verdaderamente refrescante.</p><p>Ciertamente para un lenguaje no tan popular como Erlang, no sé si es estrictamente útil aprender a decir <em>guión</em> en lugar de <em>script</em>, pues lo más probable es que si tienes una duda y quieres buscar ayuda en la internet, necesites expresarte en inglés de todos modos. Pero para un libro como el de <a href="https://medium.com/u/7081b45b4fd3">Manuel</a>, es algo que le aporta carácter sin enturbiar la comprensión del contenido.</p><h4>Erlang sin OTP</h4><p>Otra cosa que <a href="https://medium.com/u/7081b45b4fd3">Manuel</a> se encarga de mencionar en el libro y que es algo que yo he aprendido un poco a la fuerza a lo largo de mi carrera enseñando Erlang a desarrolladores es que, si bien es muy tentador introducir OTP desde el primer momento, eso no es necesario. De hecho, que el libro sea tan completo y aún así sólo mencione OTP <em>al pasar </em>nos muestra a la vez la simplicidad y el poder que tiene Erlang como lenguaje y la BEAM como máquina virtual.</p><p>Es cierto que nadie (salvo quizá quienes trabajen para <a href="https://medium.com/u/1dee40c5d1d3">Ericsson</a>) va a conseguir nunca un trabajo de desarrollador Erlang que no incluya el conocimiento de OTP, pero también es cierto que para entender OTP apropiadamente es vital tener un conocimiento de Erlang y su máquina virtual en general. Así que este libro es importantísimo y, tal como su autor se encarga de manifestar, es <em>sólo el comienzo</em>. Hay mucho más por aprender!</p><h4>Pattern-Matching</h4><p>Cuando doy cursos de Erlang, generalmente dedico varias horas a explicar en detalle cómo funciona y para qué se usa el <em>pattern-matching</em>. Creo que lo hago así porque generalmente asumo que mi audiencia tiene cierta experiencia en programación de lenguajes del paradigma imperativo y, por eso, el concepto es algo revolucionario y sorpresivo. Además, las veces que lo he explicado velozmente, he tenido que volver a explicarlo/repasarlo al momento de enseñar funciones recursivas.</p><p><a href="https://medium.com/u/7081b45b4fd3">Manuel</a> realiza una aproximación distinta al tema en su libro. De hecho, la <em>concordancia</em> (que es así como la llama) es algo que casi no se detiene a explicar en ningún momento. Simplemente la vemos aparecer por todos lados directamente cuando se necesita usarla. Me resulta muy interesante ver ese enfoque que, entiendo, surge de asumir que el lector no es necesariamente alguien que ya sabe programar. El libro está apuntado incluso a aquellos para quienes Erlang es su primer lenguaje de programación y por tanto, no tienen que <em>desaprender</em> nada.</p><h4>Más allá de Erlang</h4><p>Siguiendo este mismo criterio (asumir un público no <em>iniciado</em>), el libro no pasa por alto ninguna explicación relevante aunque no esté directamente relacionada con el lenguaje que está explicando. Así es como en un libro introductorio a Erlang, no econtramos con lecciones sobre protocolos de red, seguridad informática, algorítmos y varias otras cosas que le brindan una robustez muy satisfactoria a lo que uno está leyendo. No se necesita abandonar el libro para googlear nada, toda la información está allí mismo.</p><h4>El Órden de los Tópicos</h4><p>Finalmente, creo que mi única <em>crítica</em>, más allá de uno o dos pequeños errores que se han filtrado en el texto, acerca del libro es que es una montaña rusa de emociones.</p><p>Quizá sea porque a lo largo del tiempo me he acostumbrado a enseñar Erlang (y otros lenguajes de programación) siguiendo un orden más o menos similar todas las veces, pero el órden elegido por <a href="https://medium.com/u/7081b45b4fd3">Manuel</a> me resulta, al menos, sorprendente e inesperado.</p><p>En el libro pasamos de <em>Tipos de Datos</em> a <em>Tiempo Real Blando</em> sin mediar explicación alguna de algorítmos, módulos, funciones. Pasamos luego de case e if directo a listas por comprehensión. Yo hubiese esperado un poco de recursión antes de irnos tan lejos, quizá. Lo mismo cuando pasamos de funciones anónimas (o clausuras) directo a las directivas del preprocesador. Es un libro que nunca para de sorprender al lector, eso es seguro! 😏</p><h3>Conclusión</h3><p>En conclusión, como lo decía al principio, <strong>Erlang/OTP: Un Mundo Concurrente</strong> es un fabuloso libro para aprender Erlang de cero, en castellano y sin necesidad de tener conocimientos previos de programación, redes, concurrencia, seguridad informática, ni nada más.</p><p>Pero claro, siempre es conveniente presentar esta advertencia:</p><blockquote>Erlang es <em>un viaje de ida</em>. Una vez que hayas conocido todas las cosas maravillosas que puedes hacer con este simple lenguaje y esta potente máquina virtual, ya no verás con los mismos ojos al resto.</blockquote><p>Te lo digo por experiencia… 😉</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a9d86564159d" width="1" height="1" alt=""><hr><p><a href="https://medium.com/erlang-battleground/erlang-otp-un-mundo-concurrente-a9d86564159d">Erlang/OTP: Un Mundo Concurrente</a> was originally published in <a href="https://medium.com/erlang-battleground">Erlang Battleground</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Erlang’s Halloween ]]></title>
            <link>https://medium.com/erlang-battleground/erlangs-halloween-ceffd057dc8b?source=rss-788b9596f013------2</link>
            <guid isPermaLink="false">https://medium.com/p/ceffd057dc8b</guid>
            <category><![CDATA[halloween]]></category>
            <category><![CDATA[dialyzer]]></category>
            <category><![CDATA[static-analysis]]></category>
            <category><![CDATA[erlang]]></category>
            <dc:creator><![CDATA[Brujo Benavides]]></dc:creator>
            <pubDate>Tue, 26 Oct 2021 17:22:15 GMT</pubDate>
            <atom:updated>2021-10-26T17:22:15.754Z</atom:updated>
            <content:encoded><![CDATA[<h4>Some dead code that not even Dialyzer can find</h4><p>It’s relatively unusual to watch me talking about the shortcomings or limitations of such an excellent tool as <a href="http://erlang.org/doc/apps/dialyzer/dialyzer_chapter.html">Dialyzer</a>. Still, today I found some <em>very dead code blocks</em> that slipped through its world-famous success type analysis.</p><p>So, since Halloween is close, let’s raise some dead code from its grave!</p><figure><img alt="Zombie Programmer" src="https://cdn-images-1.medium.com/max/662/1*sD8lJWOU7WBhOofGtXLhZQ.png" /><figcaption>By <a href="https://zombieprogrammer.com/">Zombie Programmer</a> — A great blog. Check it out!</figcaption></figure><h3>When Dialyzer produces a Warning</h3><p>So, in the past, I’ve seen code like this one…</p><pre><strong>warn</strong>(X) -&gt;<br>    {<strong>just</strong>, X};<br><strong>warn</strong>(6) -&gt;<br>    {<strong>six</strong>, 6}.</pre><p>Trigger warnings from both the compiler and Dialyzer like the following ones…</p><pre><em>===&gt; Compiling my_app</em><br><strong>src/el.erl:8</strong>: Warning: this clause for warn/1 <strong>cannot match</strong> <strong>because</strong> <strong>a previous clause</strong> at line 6 <strong>always matches</strong></pre><pre><em>===&gt; Dialyzer starting, this may take a while...<br>…</em></pre><pre>src/el.erl<br><strong>Line 8:</strong> The pattern 6 <strong>can never match</strong> <strong>since</strong> <strong>previous clauses</strong> <strong>completely</strong> <strong>covered the type any()</strong><br></pre><p>Lovely! The second clause in that function is <em>clearly</em> dead code (i.e., it will never be evaluated) since <strong>6 </strong>matches <strong>X </strong>and thus falls through the first clause when provided as input. This is one of my favorite Dialyzer warnings ever. It’s clear and actionable. It provides a proper context with line numbers and what-not. It’s awesome.</p><h3>When Dialyzer doesn’t produce a Warning</h3><p>But… Today I found a piece of dead code that was very, very similar and yet… Dialyzer and the Compiler were both <em>utterly silent</em> about it. Let me show you…</p><pre><strong>warn</strong>(X, X) -&gt;<br>    {<strong>just</strong>, X};<br><strong>warn</strong>(6, 6) -&gt;<br>    {<strong>six</strong>, 6}.</pre><p>Have you spotted the difference?<br>Let me show you yet another example…</p><pre><strong>warn</strong>(X, Y) -&gt;<br>    {<strong>just</strong>, X <strong>and</strong> Y};<br><strong>warn</strong>(6, 6) -&gt;<br>    {<strong>six</strong>, 6}.</pre><p>This one <em>does </em>produce the expected warnings…</p><pre><em>===&gt; Compiling my_app</em><br><strong>src/el.erl:8</strong>: Warning: this clause for warn/2 <strong>cannot match because a previous clause</strong> at line 6 <strong>always matches</strong></pre><pre><em>===&gt; Dialyzer starting, this may take a while...<br>…</em></pre><pre>src/el.erl<br><strong>Line 8</strong>: The pattern &lt;6, 6&gt; <strong>can never match since previous clauses completely covered the type &lt;_,_&gt;</strong></pre><h3>What’s Going on Here?</h3><p>Well… It seems that not every clause that cannot match can be detected by either the compiler or Dialyzer. Sadly, those that include bounded variables (like the second <strong>X</strong> in <strong>warn/2</strong>) or guards or any other <em>semantic</em> constructs are outside the scope of these detection tools.</p><p>So, if you have functions like that, the compiler and Dialyzer won’t detect your dead code, and it may end up living as a ghost for a long, long time.</p><p>Well, in that case, <em>who you’re gonna call?</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*NNlzggasBOYKszvHB4jhaw.jpeg" /><figcaption>No, not the Ghost Busters</figcaption></figure><p><strong>Test Coverage, </strong>of course!</p><p>If you have a good test coverage policy in place (maybe one like the <a href="https://medium.com/u/ff261d008b59">Inakos</a> had where we demanded <strong>100% coverage</strong> everywhere, perhaps a lighter one), you should immediately see that no test can ever cover those clauses. Then, you can remove them.</p><p>As usual, if you like my blog, you can <a href="https://www.buymeacoffee.com/elbrujohalcon">buy me a coffee</a> and if you want to participate, we’re always looking for new writers for <strong>Erlang Battleground</strong>. Hit me up on Twitter, Facebook, Slack, etc.…</p><h3>Bonus Track</h3><p>While writing this article, I checked several other scenarios to see what was detectable and what was not. You can see the module I used for that below…</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1110005c9c11645c1de1fdc587652854/href">https://medium.com/media/1110005c9c11645c1de1fdc587652854/href</a></iframe><p>And these are the only warnings that I get with it…</p><pre>===&gt; Analyzing applications...<br>…<br>===&gt; Compiling lapp<br><strong>src/el.erl:8:</strong> Warning: this clause for warn/2 cannot match because a previous clause at line 6 always matches<br><strong>src/el.erl:19:</strong> Warning: this clause cannot match because a previous clause at line 17 always matches<br><strong>src/el.erl:25:</strong> Warning: this clause cannot match because a previous clause at line 23 always matches<br><strong>src/el.erl:27:</strong> Warning: this clause cannot match because a previous clause at line 23 always matches</pre><pre>===&gt; Dialyzer starting, this may take a while...<br>…</pre><pre><strong>src/el.erl</strong><br><strong>Line 8:</strong> The pattern &lt;6, 6&gt; can never match since previous clauses completely covered the type &lt;_,_&gt;<br><strong>Line 19:</strong> The pattern &lt;&gt; can never match since previous clauses completely covered the type &lt;&gt;<br><strong>Line 25:</strong> The pattern 6 can never match since previous clauses completely covered the type any()<br><strong>Line 27:</strong> The variable _ can never match since previous clauses completely covered the type any()</pre><blockquote>If you find more scenarios worth mentioning, please write a comment about them below.</blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ceffd057dc8b" width="1" height="1" alt=""><hr><p><a href="https://medium.com/erlang-battleground/erlangs-halloween-ceffd057dc8b">Erlang’s Halloween 👻</a> was originally published in <a href="https://medium.com/erlang-battleground">Erlang Battleground</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Oh, Erlang! ]]></title>
            <link>https://itnext.io/oh-erlang-885379e8bf7e?source=rss-788b9596f013------2</link>
            <guid isPermaLink="false">https://medium.com/p/885379e8bf7e</guid>
            <category><![CDATA[hackathons]]></category>
            <category><![CDATA[erlang]]></category>
            <category><![CDATA[funny]]></category>
            <category><![CDATA[emoji-stories]]></category>
            <category><![CDATA[community]]></category>
            <dc:creator><![CDATA[Brujo Benavides]]></dc:creator>
            <pubDate>Sun, 19 Sep 2021 22:16:33 GMT</pubDate>
            <atom:updated>2021-10-12T11:53:45.751Z</atom:updated>
            <content:encoded><![CDATA[<h4>What we did for #SpawnFest 2021</h4><p>For almost ten years, I waited patiently but actively. And finally, the time has come! I was able to participate again in my all-time favorite hackathon: <a href="https://spawnfest.org/"><strong><em>SpawnFest</em></strong></a>. In this article, I’ll show how Mariano, <a href="https://medium.com/u/7081b45b4fd3">Manuel</a>, Tetiana, and I spent the last 48 hours <em>emojifying</em> as many Erlang modules as possible.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/460/1*leSUi1F2rbsucrz87MmKxA.jpeg" /><figcaption>Yes, that’s us!</figcaption></figure><h3>Background</h3><p>Let me start with a bit of personal history… 👴🏻</p><p>Back in 2011, when I was one of the youngest <a href="https://medium.com/u/ff261d008b59">Inakos</a> in Buenos Aires, <a href="https://medium.com/u/57773967d56e">Chad</a> (or is it <a href="https://medium.com/u/e325456b4d2c">Chad</a>?), Manuel, <a href="https://medium.com/u/cfaa95384131">Marcos</a>, and I spent two days locked in a house writing Erlang code for a contest. That contest was the first SpawnFest ever. It was a truly fantastic experience, particularly for people living far away from the leading developer community centers of the world.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2Fsm9QB_OyB9w&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3Dsm9QB_OyB9w&amp;image=http%3A%2F%2Fi.ytimg.com%2Fvi%2Fsm9QB_OyB9w%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/16e0596441e0ee9821b5476567b84cef/href">https://medium.com/media/16e0596441e0ee9821b5476567b84cef/href</a></iframe><p>We played again the following year. But then, after its second edition, the organizers discontinued the contest. 😢</p><p>We waited for a while… ⏲ … hoping to be able to participate again.</p><p>Five years later, in 2017, <a href="https://medium.com/u/cfaa95384131">Marcos</a> and I decided to take matters into our own hands: We started organizing the contest. We did it basically <em>from scratch, </em>but we were very fortunate to have many people helping us with it. We organized 2017, 2018, and 2019 editions (the last two with <a href="https://medium.com/u/e152fdf17cbf">Juan</a> and <a href="https://medium.com/u/8d1ce1f48bb0">Darío</a>, too).</p><p>It still is one of the most rewarding experiences of my life. I would do it again millions of times if it was only up to me. But I was still longing for the chance to <strong>play</strong> again. That, plus other circumstances, led us to seek the help of Fiqus to organize the event in 2020. Still, those same circumstances prevented me from building a team and competing in the event. I ended up helping the organizers a bit. 🤷‍♂</p><p>This year, we also started looking for other folks to take care of the organization (this time <em>indefinitely</em>)<em> </em>and luckily we found <em>The Fellowship of the BEAM </em>(<a href="https://medium.com/u/5fc59fe20548">Pablo</a>, Paulo, <a href="https://medium.com/u/70fb8775dcea">Bryan</a>, and Filipe from The Erlang Ecosystem Foundation).</p><p>Almost 10 years after the last time, I was finally able to play again! 🎉</p><h3>BEAMoji 🪄</h3><p>It took us quite a while to build the team, but from the get-go, we had a very clear idea of what we wanted to achieve in this contest:</p><blockquote>We wanted to have fun, not rush</blockquote><blockquote>and build something just for the fun of it.</blockquote><p>And that’s exactly what we did. <br>We wrote the funniest rebar3 plugin ever: <a href="https://hex.pm/packages/beamoji"><strong>BEAMoji</strong></a><strong>.</strong></p><h4>What is BEAMoji? 🤌</h4><p>BEAMoji is a plugin that adds the rebar3 emojify command, which allows you to turn all the boring atoms in your code into funny, creative, progressive, and (why not?) auto-localized… <strong>emojis!</strong></p><p>Do you want an example? Say no more…</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/922/1*sRg4j05nTocPwSqsZvD1RQ.gif" /></figure><p>Do you want to test it yourself? Of course…</p><p>Add this to your rebar.config:</p><pre>{deps, [<strong>beamoji</strong>]}<br>{project_plugins, [<strong>beamoji</strong>]}.</pre><p>Then update your deps and run…</p><pre>$ rebar3 emojify</pre><p>You should see something like this as output…</p><pre>===&gt; <strong>emojifying</strong> your code with beamoji_emojilist_translator…<br>===&gt; <strong>emojifying</strong> src/your_module.erl with beamoji_emojilist_translator…</pre><p>Then, your module would’ve changed from… 😑</p><pre><strong>search</strong>(P, [H | T]) -&gt;<br>    case P(H) of<br>        <strong>true</strong> -&gt;<br>            {<strong>value</strong>, H};<br>        <strong>false</strong> -&gt;<br>            <strong>search</strong>(P, T)<br>    end;<br><strong>search</strong>(P, []) -&gt;<br>    <strong>false</strong>.</pre><p>…to… 😱</p><pre>&#39;🆘👀🍎🌈💿️❤️&#39;(P, [H | T]) -&gt;<br>    case P(H) of<br>        &#39;🦖🌈🦄👀&#39; -&gt;<br>            {&#39;✌️🍎🦙🦄👀&#39;, H};<br>        &#39;🔥🍎🦙🆘👀&#39; -&gt;<br>            &#39;🆘👀🍎🌈💿️❤️&#39;(P, T)<br>    end;<br>&#39;🆘👀🍎🌈💿️❤️&#39;(P, []) -&gt;<br>    &#39;🔥🍎🦙🆘👀&#39;.</pre><p>…or… 🤩</p><pre>&#39;👀️&#39;(P, [H | T]) -&gt;<br>    case P(H) of<br>        &#39;✔️&#39; -&gt;<br>            {&#39;⚖️&#39;, H};<br>        &#39;❌&#39; -&gt;<br>            &#39;👀&#39;(P, T)<br>    end;<br>&#39;👀&#39;(P, []) -&gt;<br>    &#39;❌&#39;.</pre><p>…depending on what <em>translator</em> you decide to use.</p><h4>Translators 🗣</h4><p>BEAMoji comes with 3 translators that you can pick using rebar emojify — translator your_favorite_translator. Each of them will turn your atoms into emojis (and back) using a different strategy:</p><ul><li><strong>EmojiList:</strong> This translator is the default one. It has a dictionary of known atoms and it maps each one to a sensible emoji. You can see it in action in the last example above.</li><li><strong>BaseEmoji:</strong> This translator started as something like a Base64 with emojis, but we made it a bit more <em>intuitive</em> along the way. Check if you can find the relationship between the emojis and what they represent! 🕵️‍♂️</li><li><strong>MultiWords:</strong> This translator is like <strong>EmojiList</strong>, but it can handle multiple words in an atom as long as you write them using snake_case.</li></ul><h4>Parse Transformation ⏪</h4><p>Just replacing the atoms with their emojified versions would likely break your code, since many atoms have specific meanings like true, false, undefined, error, ok, etc. Many of them are used as module and function names, too. We couldn’t <em>just</em> emojify them.</p><p>To make the emojified modules work we add attributes during the translation to run a parse transform and tell it which translator was originally used so that the parse transform can “demojify” the module before it’s sent to the compiler.</p><p>In this way emojis are for humans, the compiler sees the module as if no translation was done. It’s a little secret between you and us. 🤫</p><h3>Lessons Learned 🤓</h3><p>Turning words into emojis is not a trivial task. We achieved our goals during the weekend. We even published the project on hex.pm. But we had to work around a few obstacles along the way, and we learned quite a few valuable lessons with those experiences. We detailed them all <a href="https://github.com/spawnfest/beamoji/blob/%E2%93%82%EF%B8%8F/ACHIEVEMENTS.md"><strong>in the repo</strong></a>. Go check them out! There’re a couple of funny bits here and there.</p><p>And we wanted to share this learning experience with everyone. So we want to invite you to keep learning with us. For that, we prepared one of the world-famous CleverBunny 🐇 quizzes. <a href="https://quiz.elixircards.co.uk/BEAMoji">Jump in on it and check your emoji-skills!</a></p><figure><a href="https://quiz.elixircards.co.uk/BEAMoji"><img alt="" src="https://cdn-images-1.medium.com/max/771/1*0_W7d3Ror1skoB9a0OvZag.png" /></a></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=885379e8bf7e" width="1" height="1" alt=""><hr><p><a href="https://itnext.io/oh-erlang-885379e8bf7e">Oh, Erlang! 🤯</a> was originally published in <a href="https://itnext.io/">ITNEXT</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Galicia ❤️ The BEAM]]></title>
            <link>https://medium.com/erlang-battleground/galicia-%EF%B8%8F-the-beam-7e7b732b510c?source=rss-788b9596f013------2</link>
            <guid isPermaLink="false">https://medium.com/p/7e7b732b510c</guid>
            <category><![CDATA[galicia]]></category>
            <category><![CDATA[community]]></category>
            <category><![CDATA[elixir]]></category>
            <category><![CDATA[erlang]]></category>
            <dc:creator><![CDATA[Brujo Benavides]]></dc:creator>
            <pubDate>Tue, 13 Jul 2021 06:02:44 GMT</pubDate>
            <atom:updated>2021-07-13T06:02:44.705Z</atom:updated>
            <content:encoded><![CDATA[<h4>The impressive Galician contributions to the Erlang Ecosystem</h4><p>We all know about the most renowned Erlang/Elixir centers worldwide, like Sweden, Brazil, California, and London. But the community, even when not huge, is broadly spread. Today we want to celebrate a smaller region that’s home to many amazing contributions to our beloved ecosystem. The birthplace of my ancestors: <strong>Galicia!</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gO7i9L2T0ObJG7w2rWD77g.jpeg" /><figcaption>The other shell that we love so much 🥰</figcaption></figure><p>So, in this <em>unusual style</em> (a <a href="https://medium.com/@pablocostass/12d32908cc92?source=friends_link&amp;sk=489710101fb56d3e1eb5bdf9a4466d0d">collaborative bilingual</a> interview-like article), we’re going to showcase 4 of the many Galicians that have had a profound impact on the language and the people around it…</p><h3>Laura M. Castro</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/400/1*GuEW_2tDNxw27j8jkP67Wg.png" /><figcaption><a href="https://lauramcastro.github.io/">Laura</a></figcaption></figure><blockquote>Ghuapo, ghuapo non é… pero ten uns procesos!!!</blockquote><p><a href="https://medium.com/u/5a2796fff46e">Laura</a> got her first Erlang-related “job” (it was a summer internship in the fourth year of her career) because after having taken an elective course called “Functional Programming,” where she learned the language, all she could do was talking to her classmates about its wonders non-stop. She was fascinated with how easy it was to work with multiple processes, multiple nodes, and … <strong>reloading code without having to stop the system!!</strong></p><p>One day, while at the student representatives’ premises (of whom she was part), someone called to offer an internship. As soon as they mentioned “functional” and “Erlang,” someone handed her the phone without saying another word.</p><p>Thanks to that opportunity, the following course, she wrote her Final Thesis exploring how objects could be “simulated” (OOP was starting to take over at the time) in Erlang (using structures, using processes). That Thesis led her to participate in developing a risk assessment system for a large multinational company, which backend was entirely written in Erlang. The first articles arrived at the Erlang Workshop recounting the experience, and the academic world bug bit her. It started with her thesis, then becoming an assistant professor, getting a doctorate … <em>the rest is history!</em></p><h4>When / How did you take your first steps in the Erlang ecosystem?</h4><blockquote>Beyond using the language and reading the mailing lists, my diving into the community coincided with my predoctoral visits to Sweden, hosted by Thomas Arts (now Quviq AB). Being in Gothenburg, it was easy to get to Stockholm, the center where it all started! The Erlang User Conferences helped me put faces together with names, one thing led to another, you know…</blockquote><h4>What motivated you the most to contribute to the community?</h4><blockquote>I have always been (even before I met Erlang!) a heartfelt advocate of free software, so contributing, for me, is at the core of software development work.</blockquote><h3>Prowess</h3><p>One of the multiple contributions from <a href="https://medium.com/u/5a2796fff46e">Laura</a> to the community is her participation in the <a href="https://cordis.europa.eu/project/id/317820"><strong>Prowess Project</strong></a>. A three-year innitiative that got companies and universities from several European countries researching together on methods and tools to improve the quality of web services. Their output was a <a href="https://github.com/prowessproject">swath of Erlang open-source libraries</a>.</p><h4>What’s that thing that stands out about Prowess?</h4><blockquote>The work that was done, side by side, between companies and universities together trying to design useful tools for the community.</blockquote><h4>How can people participate, help, or just learn more about it?</h4><blockquote>Follow the code! There are articles, presentations at Erlang Factories, Erlang User Conferences, Erlang Workshops …</blockquote><h4>What’s your advice for the next generation of Galician BEAMers?</h4><p><em>(this one in Spanish, considering the target audience)</em></p><blockquote>Yo no empecé a programar con 10 años. Llegué a la universidad sabiendo escribir en un procesador de textos y poco más. Tenía la sensación de que todo el mundo me llevaba mucha ventaja.<br>Pero la programación funcional era desconocida para la gran mayoría (y lo sigue siendo, aunque cada vez menos). Además de gustarme, sentí que si me especializaba en ella, sería más fácil destacar. Sería más fácil conectar con otras personas con una sensibilidad parecida.<br>No me equivoqué.<br>Mi madre siempre ha dicho: “¡Vale más ser cabeza de ratón, que cola de león!”</blockquote><h3>Pablo Costas Sanchez</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/400/1*GmxCllTT5ZQBRmOLl-GhMQ.png" /><figcaption><a href="https://pablocostass.github.io/">Pablo</a></figcaption></figure><blockquote>Se ten que errar, que erre!</blockquote><p>For <a href="https://medium.com/u/5fc59fe20548">Pablo</a>, everything started back in college. Most of their courses were focused on Java and other imperative languages, which he liked but never to this point; thankfully, they were also taught the basics of functional programming and later on in the <em>Concurrency &amp; Parallelism</em> course had an assignment in Erlang. He found this language so intriguing and interesting that he ended up asking the professor for a book to learn more about it. Javier Paris, the professor, recommended <a href="https://pragprog.com/titles/jaerlang2/programming-erlang-2nd-edition/"><em>Programming in Erlang</em> by Joe Armstrong</a>. Pablo binge-read it, and that moment defined his love for the language.</p><p>Then he had a course by <a href="https://medium.com/u/5a2796fff46e">Laura</a>, although this one was in Elixir, which was so damn fun and practical that he tagged along with a friend and participated in that year’s <a href="https://spawnfest.org/">SpawnFest</a>. After that, he knew for sure that he wanted Laura to be his dissertation supervisor. A year later, she proposed the idea of parallelizing <a href="https://github.com/proper-testing/proper/">PropEr</a>, and he liked it. Jump a few months of hard work and a few talks with Kostis Sagonas into the future, and there it is: <a href="https://github.com/proper-testing/proper/pull/263">PropEr now has parallel and distributed executions!</a></p><h4>When / How did you take your first steps in the Erlang ecosystem?</h4><blockquote>I got into the community because I had an amazing experience during Lambda Days 2020 in Kraków, where I met wonderful peers (pun intended, I owe you all a dinner) and decided I wanted to help grow the community and for it to continue being as awesome as it is. I got my chance at this when <a href="https://medium.com/u/788b9596f013">Brujo Benavides</a> asked for help organising SpawnFest, to which my fellow members <a href="https://medium.com/u/70fb8775dcea">Bryan Paxton</a>, Paulo and Filipe chimed in.</blockquote><h4>What motivated you the most to contribute to the community?</h4><blockquote>Being part of a community means giving back to it when possible. I consider that true both for the open-source software we all depend on and for ecosystems themselves, such as the BEAM community. Given that, the next logical step was actually helping out :)</blockquote><h3>SpawnFest</h3><p><a href="https://spawnfest.org/">SpawnFest</a> is an annual 48-hour online software development contest in which teams from around the world get exactly one weekend to create the best BEAM-based applications they can. Participation in SpawnFest is 100% <strong>Free of Charge,</strong> and <em>all BEAM languages are welcome!</em></p><p>This year, it’s organized by <em>The Fellowship of the Beam </em>(which, of course, includes <a href="https://medium.com/u/5fc59fe20548">Pablo</a>).</p><h4>What’s that thing that stands out about SpawnFest?</h4><blockquote>Seeing folks from all over the community come together to build these amazing ideas is really inspiring ❤</blockquote><h4>How can people participate, help, or just learn more about it?</h4><blockquote>Sign up for the event if you have not already! You can either register your own team of friends or fill in another form to have us hook you up with a team; we can’t wait to see you there!</blockquote><h4>What’s your advice for the next generation of Galician BEAMers?</h4><p><em>(this one in Galician, considering the target audience)</em></p><blockquote>Antes de nada, benvid@s ao clube da xente guai ;)<br>Agora en serio, se vos gusta a BEAM, xa sexa por Erlang ou por Elixir, tendes empresas de sobra e traballos dabondo: hai unha empresa en A Coruña mesmamente e se non, hoxe en día, a gran maioría aceptan traballo remoto, así podedes ver mundo se queredes ou seguir disfrutando das terras galegas.<br>En calqueira caso, se tendes dúbidas, poñédevos en contacto :)</blockquote><h3>Brujo Benavides</h3><p><em>(yes, me… deal with it </em>😎<em>)</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/400/1*4IA2Tf0r-bnyXdb7kW97KA.png" /><figcaption><a href="https://about.me/elbrujohalcon">Brujo</a></figcaption></figure><blockquote>Fai que funcione, logo faino bonito e, se realmente o necesitas, faino rápido. O 90 por cento das veces, se o fas fermoso, xa será rápido. Entón, realmente, simplemente faino bonito!</blockquote><p><a href="https://medium.com/u/788b9596f013">Brujo</a> started writing code when he was 10, on a Commodore, at school. From then on, he never stopped. He moved from BASIC to QBasic, to Visual Basic, to .NET… until he found Haskell and Smalltalk at the University.<br>Then, Novamens was looking for someone willing to learn Erlang to develop a VoIP server with it. Brujo immediately fell in love with the language. A few years later, after joining Inaka, he was already giving his first talk at the Erlang Factory SF in 2012 and answering questions from no other than Joe Armstrong himself. 🤯</p><h4>When / How did you take your first steps in the Erlang ecosystem?</h4><blockquote><a href="https://medium.com/u/ff261d008b59">Inakos</a>’ culture was tightly bound to open-source and, as such, we contributed many many projects, tools and libraries that we are still maintaining today, even when the company was dissolved in 2017.<br>After joining <a href="https://medium.com/u/52467e7eae7d">Erlang Solutions</a>, I became a trainer, too and I had the honor to deliver some lessons with <a href="https://medium.com/u/68e3df6c3d43">Robert Virding</a>, among others.</blockquote><blockquote>I started writing this blog back in 2016, mostly to collect the funny bits of my experience with the language, but it grew so much beyond that. So, when the <a href="https://erlef.org/">Erlang Ecosystem Foundation</a> became a thing… I knew I had to join!</blockquote><blockquote>Now, I work at NextRoll (previously known as <a href="https://medium.com/u/395e9bbfc300">AdRoll</a>), a company that also has an amazing culture and gives me and my colleagues lots of chances to keep contributing back to the community, particularly building development tools and mentoring people.</blockquote><h4>What motivated you the most to contribute to the community?</h4><blockquote>I’m a big fan of open-source, in general. We use tons of open-source software every day, every second… If we have the chance to contribute back to the people who developed it and forward to more people that may use our tools, I think we must.<br>Now, particularly for the Erlang Ecosystem, this is a community that welcomed me with open-arms even when I was just some totally unknown mate-drinker from the far south. At the time, that was totally unusual for me and I valued it a lot. It made my desire to contribute even stronger and it still does to this day. Lately, I’ve been developing tools for Erlang (like the formatter, hank, elvis, etc.) mostly because I felt that was one of the things Erlang devs needed the most.</blockquote><h3>Hank</h3><p><a href="https://hex.pm/packages/rebar3_hank">rebar3_hank</a> is an <em>oxbow code</em> detector for Erlang. It helps you remove dead code that pollutes your projects, like unused macros, unused record fields, and other nasty stuff…</p><p>It is developed by <a href="https://medium.com/u/ef970f2a0a41">Pablo Brud</a>, <a href="https://medium.com/u/42242c060db0">Diego Calero</a>, and <a href="https://medium.com/u/788b9596f013">Brujo</a>… and it will soon have an associated paper published by <a href="https://medium.com/u/5a2796fff46e">Laura</a> and <a href="https://medium.com/u/788b9596f013">Brujo</a> for the <a href="https://icfp21.sigplan.org/home/erlang-2021">Erlang Workshop at the upcoming ICFP2021</a>.</p><h4>What’s that thing that stands out about Hank?</h4><blockquote>The best thing about Hank is that it’s a tool that other languages don’t have! It might as well be the first time in a long long time that you can do something with your Erlang code, that you can’t do in your Elixir projects. <em>😎</em><br>From a personal perspective, as well, it opened up the doors of the scientific community for me. We were able to write an academic paper about it and give this small hackweek project a certain class and elegance that others don’t have. It can now sit at the grown-ups table, with dialyzer, RefactorErl, and others.</blockquote><h4>How can people participate, help, or just learn more about it?</h4><blockquote><strong>Use it!</strong> Find bugs and report them.<br>And, of course, send all the PRs to <a href="https://github.com/AdRoll/rebar3_hank">https://github.com/AdRoll/rebar3_hank</a></blockquote><h4>What’s your advice for the next generation of Galician BEAMers?</h4><p><em>(this one in Spanish, considering the target audience)</em></p><blockquote>El mundo de la BEAM no es sencillo para los recién llegados, eso es cierto.<br>No hay escasez de buenos trabajos, pero la mayoría de ellos requiere cierto nivel de experiencia y conocimiento que impide que los estudiantes o recién graduados ingresen fácilmente.<br>Se están realizando esfuerzos para superar esta brecha. Empresas como <a href="https://medium.com/u/52467e7eae7d">Erlang Solutions</a> o <a href="https://medium.com/u/975a109613a1">LambdaClass</a> tienen programas de capacitación que pueden ayudarlos a obtener la experiencia deseada, y no están solas. Pero es cierto que las oportunidades laborales no surgen en todos los rincones, como ocurre con otros lenguages.<br>Por otro lado, una vez que se consigue un trabajo en un proyecto basado en la BEAM, <strong>no hay vuelta atrás</strong>. Nada se sentirá igual después de esa experiencia. No necesitan confiar en mi palabra, simplemente observen cuántos lenguajes están agregando soporte para modelo de actores, pattern-matching, árboles de supervisión, deep tracing… Todas cosas que Erlang ya proveía cuando yo lo conocí hace más de una década… Les garantizo que, una vez que tengan todas esas herramientas a su disposición, van a querer usarlas donde quiera que vayan.<br>En pocas palabras: conseguir su primer trabajo con Erlang o Elixir puede ser un desafío, <strong>¡pero es uno que realmente vale la pena!<br></strong>Y una forma realmente genial y divertida de comenzar ese proceso es participar de SpawnFest y/o solicitar <a href="https://erlef.org/stipends/">una beca de estudios de la EEF</a>.</blockquote><h3>Miriam Pena</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/400/1*_TodaAfX5-R40ZowXVqI5g.png" /><figcaption><a href="https://www.linkedin.com/in/miriampena/">Miriam</a></figcaption></figure><blockquote>“nunca choveu que non escanpara”</blockquote><blockquote>(repetir para si cando as cousas rompen en produción)</blockquote><p><a href="https://medium.com/u/6f7f40d7903e">Miriam Pena</a> is a computer engineer, graduated from the University of A Coruña who is passionate about building computer systems distributed over several continents that work for millions of simultaneous users. She has worked as an Erlang specialist worldwide, including Sweden, Egypt, the USA, Ireland, and Spain.</p><p>Two years ago, she founded, along with other community leaders from Erlang and Elixir, a non-profit foundation called the <a href="https://erlef.org/">Erlang Ecosystem Foundation</a>, based in California. Miriam is a member of the board of directors and also leads its Education working group. This non-profit foundation is dedicated to promoting technologies and languages ​​such as Erlang and Elixir, based on the Erlang virtual machine.</p><p>She got the Ada Byron Award in 2018 from the Galician College of Computer Engineers and was listed as one of the <a href="https://you.women2.com/12-inspiring-female-staff-engineers-to-watch-b487b39558e1"><em>Inspiring Female Staff Engineers to Watch</em></a> that same year. This recognition leads her to commit to being more visible and encouraging other women to get into technology.<br> <br>Since 2015 she works at the marketing company NextRoll, in San Francisco, where she is in charge of designing and implementing critical parts of the real-time data collection used in their Marketing solutions.</p><h4>When / How did you take your first steps in the Erlang ecosystem?</h4><blockquote>My first internship was at <a href="http://www.igalia.com/">Igalia</a>, developing a V-LAN switch in Erlang. Then I did my final degree project extending that to make it work with better performance. Little by little, I fell in love with the ecosystem. Later, at <a href="http://www.nomasystems.com/">Nomasystems</a>, I developed my first highly concurrent systems in production, working on renewable energy, social networks and telecommunications systems … and I simply could not stop…</blockquote><h4>What motivated you the most to contribute to the community?</h4><blockquote>I deeply believe in the potential of the Erlang &amp; Elixir ecosystem and the community of developers that are part of it.</blockquote><h3>The Erlang Ecosystem Foundation</h3><p><a href="https://erlef.org/">The EEF</a> has a clear goal: to grow and support a diverse community around the Erlang and Elixir ecosystem by helping to develop open-source technologies and projects based on their languages and runtime.</p><h4>What’s that thing that stands out about the EEF?</h4><blockquote>From my perspective, it’s the hard work that I’m doing to increase the diversity of the community and for this reason (with the collaboration of the Education group) we are promoting initiatives that increase the number of language users around the world. Lately we are working in collaboration with conferences and workshops to be able to send students and underrepresented people in tech to conferences for free.</blockquote><h4>How can people participate, help, or just learn more about it?</h4><blockquote>Perhaps the best thing to do is to just join <a href="https://erlef.org/slack-invite/erlef">the foundation’s slack workspace</a> and start talking with us.</blockquote><h4>What’s your advice for the next generation of Galician BEAMers?</h4><p><em>(this one in Spanish, considering the target audience)</em></p><blockquote>Les animaría a probar a programar en Elixir porque tiene una gran comunidad, buena documentación, y gran demanda de trabajo bien pagado (especialmente en remoto). Las aplicaciones escritas en la BEAM escalan muy fácilmente y son fiables. Además, aprender a programar en la BEAM te va a hacer programar mejor en otros lenguajes.</blockquote><p>But <a href="https://medium.com/u/6f7f40d7903e">Miriam</a>, <a href="https://medium.com/u/5fc59fe20548">Pablo</a>, <a href="https://medium.com/u/788b9596f013">Brujo</a>, and <a href="https://medium.com/u/5a2796fff46e">Laura</a> are <em>certainly</em> not alone. There are many more Galician folks in the Erlang Ecosystem. So, stay tuned because like our grandmothers used to say…</p><blockquote>Quedaches con fame? Fágoche algunha entrevista máis?</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/537/1*K7X6DzL8oHUQsUnGSqw8bw.jpeg" /><figcaption>[Not] our grandmas reading the article — <a href="https://blogs.publico.es/strambotic/2018/12/frases-sabias-abuelos-gallegos/">Originally from Público</a></figcaption></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7e7b732b510c" width="1" height="1" alt=""><hr><p><a href="https://medium.com/erlang-battleground/galicia-%EF%B8%8F-the-beam-7e7b732b510c">Galicia ❤️ The BEAM</a> was originally published in <a href="https://medium.com/erlang-battleground">Erlang Battleground</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Spot the Difference]]></title>
            <link>https://medium.com/erlang-battleground/spot-the-difference-733a5c2fce77?source=rss-788b9596f013------2</link>
            <guid isPermaLink="false">https://medium.com/p/733a5c2fce77</guid>
            <category><![CDATA[erlang]]></category>
            <category><![CDATA[funny]]></category>
            <category><![CDATA[elixir]]></category>
            <dc:creator><![CDATA[Brujo Benavides]]></dc:creator>
            <pubDate>Tue, 22 Jun 2021 09:59:41 GMT</pubDate>
            <atom:updated>2021-06-22T09:59:41.916Z</atom:updated>
            <content:encoded><![CDATA[<h4>The erlang:process_info/1,2 version</h4><blockquote><strong>DISCLAIMER<br></strong><em>This article is not meant to be an instructive one. It’s written just for fun! </em><a href="https://lobste.rs/s/ujighk/ode_robot_butt#c_zieesf"><em>🙃</em></a></blockquote><p>Erlang is famous for its introspecting powers. You can get <strong>a lot</strong> of information about the processes running in your nodes without any <em>external</em> tool. One of the functions that provide that information is <a href="https://erlang.org/doc/man/erlang.html#process_info-1"><strong>erlang:process_info/1,2</strong></a>.</p><p>Well, this article is not about it. It’s just about this <em>unintuitive </em>but<em> understandable </em>situation we found with <a href="https://medium.com/u/926130edc832">Manuel Rubio</a> and Mário Luís Guimarães on the Erlang Slack a long time ago…</p><pre>1&gt; <strong>Pid</strong> = spawn(fun() -&gt; receive stop -&gt; ok end end).<br>&lt;0.85.0&gt;<br>2&gt; erlang:process_info(<strong>Pid</strong>) == erlang:process_info(<strong>Pid</strong>).<br><em>false</em></pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*uYZUvBHZVzlzbYa8bunwwA.png" /><figcaption><a href="https://commons.wikimedia.org/wiki/File:Spot_the_difference.png">Original @ WikiMedia Commons</a></figcaption></figure><h3>Where are the Differences?</h3><p>That situation might not seem strange to some folks. As <a href="https://medium.com/u/7081b45b4fd3">Manuel</a> pointed out…</p><blockquote>Keep in mind that between the first erlang:process_info/1 running and the second one, the World™️ is moving around 😄</blockquote><p>But I wanted to know exactly <em>what</em> was <em>moving around </em>there…</p><pre>3&gt; erlang:process_info(<strong>Pid</strong>) -- erlang:process_info(<strong>Pid</strong>).<br>[{<strong><em>reductions</em></strong>,4009}]</pre><p>OK. Clearly, the number of reductions is what’s changing…</p><pre>4&gt; {erlang:process_info(<strong>Pid</strong>, reductions), erlang:process_info(<strong>Pid</strong>, reductions)}.<br>{{reductions,<strong><em>4011</em></strong>},{reductions,<strong><em>4011</em></strong>}}</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/480/1*pZZ0I8bMb4qHxNfAv7hlMw.gif" /></figure><p>Let’s try in a different way…</p><pre>5&gt; {<strong>I1</strong>, <strong>I2</strong>} = {erlang:process_info(<strong>Pid</strong>), erlang:process_info(<strong>Pid</strong>)},<br>5&gt; {<strong>I1</strong>, <strong>I2</strong>}.<br>{[{current_function,{prim_eval,&#39;receive&#39;,2}},<br>  …<br>  {reductions,<strong><em>4011</em></strong>},<br>  …<br>  {suspending,[]}],<br> [{current_function,{prim_eval,&#39;receive&#39;,2}},<br>  …<br>  {reductions,<strong><em>4012</em></strong>},<br>  …<br>  {suspending,[]}]}<br>6&gt; f(<strong>I1</strong>), f(<strong>I2</strong>),<br>6&gt; {<strong>I1</strong>, <strong>I2</strong>} = {erlang:process_info(<strong>Pid</strong>, reductions), erlang:process_info(<strong>Pid</strong>, reductions)},<br>6&gt; {<strong>I1</strong>, <strong>I2</strong>}.<br>{{reductions,<strong><em>4013</em></strong>},{reductions,<strong><em>4013</em></strong>}}</pre><p>Alright, so… reductions are increased by one, but only when you get <em>certain pieces of information</em> from the process. Interesting.</p><h3>What’s going on here?</h3><p>But then… What are those reductions anyway?</p><p>According to <a href="https://erlang.org/doc/man/erlang.html#process_info-1">the docs</a>…</p><blockquote>{reductions, Number}</blockquote><blockquote>Number is the number of reductions executed by the process.</blockquote><p>This explanation might seem silly at first, but it does contain a vital piece of data: “<em>executed </em><strong><em>by the process</em></strong><em>”. </em>We’ll see what a reduction actually is in a second, but we already have something unexpected here. Counterintuitively, it seems that to retrieve some items from a particular process, Erlang needs to <strong>execute</strong> <strong>something</strong> <strong><em>in that process</em></strong>.</p><p>Let’s first understand what a <em>reduction</em> is in this context. Luckily, the same docs from above provide the explanation, though in a rather <a href="https://erlang.org/doc/man/erlang.html#bump_reductions-1"><em>unlikely place</em></a><em>…</em></p><blockquote>In the Beam emulator, the reduction counter is normally incremented by one for <strong>each function</strong> and <strong>BIF call</strong>. A context switch is forced when the counter reaches the maximum number of reductions for a process (4000 reductions in Erlang/OTP 19.2 and later).</blockquote><p>With this in mind, it now seems that to retrieve some information from a process, the Erlang VM needs to evaluate a function or run a BIF <em>on that process</em>. Interesting… Let’s dig a bit deeper!</p><h4>The Costly Bits</h4><p>First of all, as usual, I wanted to check if this behavior is also seen with compiled code. You know, the Erlang shell is <em>tricky </em>sometimes. But I also wanted to figure out exactly which information items were the costly ones.</p><p>I started with this simple module…</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/fa8dfa88f42649fdb7514de0dd8c227e/href">https://medium.com/media/fa8dfa88f42649fdb7514de0dd8c227e/href</a></iframe><p>The results were the expected ones…</p><pre>1&gt; c(pi), pi:check().<br>#{diff =&gt; <strong>[{reductions,8}]</strong>,<br>  pi1 =&gt;<br>      [{current_function,{pi,wait,0}},<br>       …<br><strong>       {reductions,7},</strong><br>       …<br>       {suspending,[]}],<br>  pi2 =&gt;<br>      [{current_function,{pi,wait,0}},<br>       …<br><strong>       {reductions,8},</strong><br>       …<br>       {suspending,[]}]}</pre><p>Notice how the number of reductions matches much more closely what we would expect from a simple process that doesn&#39;t do anything.</p><p>And now for the more exciting part…</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/4b653ef13755f5c58f6ca6cf8c46e35e/href">https://medium.com/media/4b653ef13755f5c58f6ca6cf8c46e35e/href</a></iframe><p>And the <em>Costly Bits of Information </em>are…</p><pre>2&gt; c(pi), pi:check().<br>[backtrace,binary,current_function,current_location,<br> current_stacktrace,dictionary,links,memory,messages,<br> monitored_by,monitors,suspending,total_heap_size]</pre><p>So, now you know…</p><blockquote>Every time you check, for instance, the list of links of a process, the Erlang VM evaluates something (consuming precisely one reduction) in that process.</blockquote><p>And that also happens when using erlang:process_info/1 because the default list of items includes current_function, dictionary, links, suspending and total_heap_size.</p><h4>Even More…</h4><p>That leads us to <em>the final mystery</em>… If, to return each of the items listed above, the Erlang VM evaluates a thing (that adds a reduction) to the process, <em>how many reductions do you think it should add if we request </em><strong><em>all </em></strong><em>those items?</em></p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9d0c3642a6137583c48b205fa8463f72/href">https://medium.com/media/9d0c3642a6137583c48b205fa8463f72/href</a></iframe><p>And the result is…</p><pre>3&gt; c(pi), pi:check().<br>1</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/358/1*Dn-7hasnISkWGOf1KI9uDQ.gif" /></figure><p>Let’s close this with the usual reminders…</p><ul><li>💪 <a href="https://spawnfest.org/">SpawnFest is coming!!</a></li><li>✍️ Erlang Battleground (this blog) is looking for writers. Please talk to <a href="https://medium.com/u/788b9596f013">Brujo Benavides</a> if you want to become part of it.</li><li>☕️ If you like what I write, you can always <a href="https://www.buymeacoffee.com/elbrujohalcon"><em>buy me a coffee</em></a><em>.</em></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=733a5c2fce77" width="1" height="1" alt=""><hr><p><a href="https://medium.com/erlang-battleground/spot-the-difference-733a5c2fce77">Spot the Difference</a> was originally published in <a href="https://medium.com/erlang-battleground">Erlang Battleground</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How do List Functions Fail in Erlang?]]></title>
            <link>https://medium.com/erlang-battleground/how-do-list-functions-fail-in-erlang-e022eec6eecd?source=rss-788b9596f013------2</link>
            <guid isPermaLink="false">https://medium.com/p/e022eec6eecd</guid>
            <category><![CDATA[erlang]]></category>
            <category><![CDATA[functional-programming]]></category>
            <category><![CDATA[semantics]]></category>
            <dc:creator><![CDATA[Brujo Benavides]]></dc:creator>
            <pubDate>Tue, 08 Jun 2021 06:28:30 GMT</pubDate>
            <atom:updated>2021-06-09T06:12:08.033Z</atom:updated>
            <content:encoded><![CDATA[<h4>Another List-Related Asymmetry</h4><p>A long time ago, I wrote an article about <a href="https://medium.com/erlang-battleground/the-asymmetry-of-validations-1ccdf2457293">The Asymmetry of ++</a>, thanks to <a href="https://medium.com/u/5d2ac21de80e">Fede Bergero</a>’s findings. Let’s add a few more asymmetries to that list…</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*R-WT0Gc-8OZln7JuO9xiBw.jpeg" /><figcaption><a href="https://www.geograph.org.uk/photo/2865891">Bridge Symmetry</a> (by <a href="https://www.geograph.org.uk/profile/307">Andy Beecroft</a>)</figcaption></figure><blockquote><strong>Note:</strong> This article is based on OTP23. Many things have been improved since that version already.</blockquote><h3>Introduction</h3><p>Initially, I thought about writing this article as a story (like I usually do), but I suddenly had too much information on my hands. So, I chose to start with a table/cheatsheet instead.</p><p>The goal of the table is to show how the different high-order functions in the lists module react when they’re given bad input, particularly in the argument where they expect a function. This bad input can be either…</p><ul><li>something that’s not a function (e.g. lists:map(not_fun, [1,2,3]) ); or…</li><li>a function with the wrong arity (e.g. lists:map(fun() -&gt; wat end, [a]) ).</li></ul><h3>Empty Lists</h3><p>Before we start and to reveal about half of the issue here, let me present you the first asymmetry:</p><pre>1&gt; lists:map(something_wrong, <strong>[1,2,3]</strong>). <strong>% A non-empty list</strong><br>** exception error: <strong>bad function</strong> something_wrong<br>     in function  lists:map/2 (lists.erl, line 1243)<br>2&gt; lists:map(something_wrong, <strong>[]</strong>). <strong>% An empty list</strong><br>** exception error: <strong>no function clause</strong> matching lists:map(something_wrong,[]) (lists.erl, line 1242)</pre><p>And this happens in all the functions you’ll see below: If you call these functions with a bad first argument and an empty list, you’ll get a function_clause error. The same happens if you call them with something that’s not a list at all. If you call them with a non-empty list, well… keep reading ;)</p><p>At least, the lists module is consistently raising function_clauseerrors when the list argument is empty. That’s <em>good</em>.</p><h3>Non-Empty Lists</h3><p>What happens when the lists are not empty? To figure that out, I used this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e16abbd122bb106e7c322538a6e33b88/href">https://medium.com/media/e16abbd122bb106e7c322538a6e33b88/href</a></iframe><p>And these are the results I got…</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3ff60179cd690101256368380874a08f/href">https://medium.com/media/3ff60179cd690101256368380874a08f/href</a></iframe><h3>Findings</h3><p>So, as you can see, while most of the functions will raise a badfun error if you don’t use a function at all, and a badarity error if you use the wrong function arity, some of them will instead raise a function_clause error in both scenarios.</p><p>For context, this is how each of those errors looks as <em>described</em> by the shell…</p><pre>10&gt; lists:foldl(not_fun, 1, [a,b,c]).<br>** exception error: <strong>bad function not_fun</strong><br>     in function  lists:foldl/3 (lists.erl, line 1267)<br>11&gt; lists:foldl(fun() -&gt; {wrong, arity} end, 1, [a,b,c]).<br>** exception error: <strong>interpreted function with arity 0 called with two arguments</strong><br>     in function  lists:foldl/3 (lists.erl, line 1267)<br>12&gt; lists:foldr(fun() -&gt; {wrong, arity} end, 1, [a,b,c]).<br>** exception error: <strong>no function clause matching </strong>lists:foldr(#Fun&lt;erl_eval.45.79398840&gt;,1,[]) (lists.erl, line 1279)<br>     in function  lists:foldr/3 (lists.erl, line 1280)</pre><p>At least from my perspective, the descriptions for the errors are clearer for lists:foldl/3 than they are for lists:foldr/3. And as I told you before, when the list is empty, <strong>all</strong> <strong>of the functions </strong>will look like lists:foldr/3(i.e., they&#39;ll raise function_clause in every bad scenario).</p><h3>Is this a Problem?</h3><p>Semantically, <strong>no</strong>. All of these functions are <em>not defined</em> for the scenarios I’m presenting so far. Therefore we shouldn’t rely on the errors that they produce when they’re called with improper values.</p><p>But, if you are new to Erlang and/or you’re trying some stuff on the console, it’s not unlikely that you call one of the functions above incorrectly. In that case, function_clause can be really confusing, while badfun or badarity ones can more easily guide you towards a solution for your problem.</p><p>Furthermore, if, for whatever reason, you need to write code that catches those errors and you don’t want to catch <em>any</em> error (only the specific ones you need), you’ll have to be careful always to handle function_clause in case your input is an empty list.</p><p>In other words, this is <strong>wrong</strong>…</p><pre>%% <strong>@doc</strong> similar to lists:all/2 but if the function has the wrong<br>%%      arity it just returns false.<br>-spec <strong>my_all</strong>(fun((...) -&gt; boolean()), [X]) -&gt; boolean().<br><strong>my_all</strong>(Pred, List) -&gt;<br>    <strong>try</strong> lists:all(Pred, List)<br>    <strong>catch<br>        error</strong>:{badarity, _} -&gt; <strong>false<br>    end.</strong></pre><p>because…</p><pre>45&gt; <strong>a_module:my_all</strong>(fun(X) -&gt; true end, [a,b,c]).<br><strong>true</strong><br>46&gt; <strong>a_module:my_all</strong>(fun() -&gt; true end, [a,b,c]).<br><strong>false</strong><br>47&gt; <strong>a_module:my_all</strong>(fun() -&gt; true end, []).<br>** exception error: <strong>no function clause matching </strong>lists:all(#Fun&lt;erl_eval.45.79398840&gt;,[]) (lists.erl, line 1216)<br>     in function  a_module:my_all/2</pre><p>So, you have to write something like…</p><pre>%% <strong>@doc</strong> similar to lists:all/2 but if the function has the wrong<br>%%      arity it just returns false.<br>-spec <strong>my_all</strong>(fun((...) -&gt; boolean()), [X]) -&gt; boolean().<br><strong>my_all</strong>(Pred, List) -&gt;<br>    <strong>try</strong> lists:all(Pred, List)<br>    <strong>catch<br>        error</strong>:{badarity, _} -&gt; <strong>false<br></strong><em>        </em><strong><em>error:function_clause</em></strong><em> </em><strong><em>when</em></strong><em> List == [] -&gt; </em><strong><em>false</em></strong><br><strong>    end.</strong></pre><h3>What would I like to see?</h3><p>I think the ideal scenario would be for all functions in the table above to have the same error behavior:</p><ul><li>If they receive something that’s not a function where they expect a function, raise badfun, regardless of list length.</li><li>If they receive a function with the wrong arity, raise badarity, regardless of list length.</li><li>If the list or any of the other parameters is wrong (e.g., not a list), raise function_clause.</li></ul><p>Basically, behave like lists:foldl/3 but don’t treat empty lists as a special case.</p><h3>Is this possible?</h3><p>Yeah! The changes in the list module are actually not that complex. Using lists:map/2 as an example, we “just” need to add these 2 clauses <a href="https://github.com/erlang/otp/blob/8b21f5c8aaa3e13046c26ecb889dae4f5dcdd70c/lib/stdlib/src/lists.erl#L1242-L1244">here</a>:</p><pre><strong>map</strong>(F, [H|T]) -&gt;<br>    [F(H)|<strong>map</strong>(F, T)];<br><strong>map</strong>(F, []) <strong>when is_function</strong>(F, 1) -&gt; [];<br><strong><em>map</em></strong><em>(F, []) </em><strong><em>when is_function</em></strong><em>(F) -&gt; </em><strong><em>error</em></strong><em>({</em><strong><em>badarity</em></strong><em>, {F, []}});<br></em><strong><em>map</em></strong><em>(_, []) -&gt; </em><strong><em>error</em></strong><em>(</em><strong><em>badfun</em></strong><em>).</em></pre><h4>Is it worth it?</h4><p>I don’t know… <em>Maybe? </em>Maybe it’s a good plan for a <a href="https://spawnfest.org/">SpawnFest</a> project? 🙃</p><p>Thanks for reading! If you like what I write and you want to encourage me to write more, you can <a href="http://buymeacoffee.com/elbrujohalcon">buy me a coffee</a> or just hit me up on the <a href="https://erlef.org/slack-invite/erlanger">Erlang Slack</a> 😊</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e022eec6eecd" width="1" height="1" alt=""><hr><p><a href="https://medium.com/erlang-battleground/how-do-list-functions-fail-in-erlang-e022eec6eecd">How do List Functions Fail in Erlang?</a> was originally published in <a href="https://medium.com/erlang-battleground">Erlang Battleground</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Ode to the Robot Butt]]></title>
            <link>https://medium.com/erlang-battleground/ode-to-the-robot-butt-bbd69e69beb2?source=rss-788b9596f013------2</link>
            <guid isPermaLink="false">https://medium.com/p/bbd69e69beb2</guid>
            <category><![CDATA[funny]]></category>
            <category><![CDATA[erlang]]></category>
            <category><![CDATA[robot-butt]]></category>
            <category><![CDATA[pattern-matching]]></category>
            <dc:creator><![CDATA[Brujo Benavides]]></dc:creator>
            <pubDate>Tue, 25 May 2021 07:44:06 GMT</pubDate>
            <atom:updated>2021-05-27T13:43:22.294Z</atom:updated>
            <content:encoded><![CDATA[<h4>…or is it to Erlang Pattern-Matching?</h4><p>Working as a mentor in the <em>Education Working Group</em> at <em>The</em> <em>EEF</em>, there are several tiny simple lessons that I’ve delivered over and over again. The one in this article is so common that I already gave it a name: <strong>The Robot Butt Rule.</strong></p><figure><img alt="Sexy robot" src="https://cdn-images-1.medium.com/max/697/1*yIMjoE9KtRS_a9XAQnXfww.png" /><figcaption>Hey, girl! 😏</figcaption></figure><p>The rule goes like this…</p><blockquote>To find if a list is not empty, don’t check its length. Use the robot butt instead.</blockquote><h3>TL;DR</h3><p>Thanks to <a href="https://twitter.com/filipevarjao/status/1397888477753139203">Filipe Varjão on Twitter</a>, you can just skip this whole article.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/676/1*3ISq1Zx0kDg6C66-4gdR2g.png" /><figcaption><strong>TL;DR</strong></figcaption></figure><h3>The Problem</h3><p>The situation usually arises when some exercise or problem requires the developer to do something with a list <em>only</em> if it is <em>not </em>empty. For instance, return its first or last element. To exemplify this scenario, let’s write a generic function for that scenario: it either returns an error if the list is empty or runs another function on the list if it’s not.</p><pre>-spec if_not_empty(<strong>FunctionType</strong>, <strong>ListType</strong>) -&gt; <strong>ErrorType</strong> | <strong>OKType</strong><br>    when <strong>FunctionType</strong> :: fun((<strong>[AnyType,...]</strong>) -&gt; <strong>AnotherType</strong>)<br>       , <strong>ListType</strong> :: <strong>[AnyType]</strong><br>       , <strong>ErrorType</strong> :: {error, empty}<br>       , <strong>OKType</strong> :: {ok, <strong>AnotherType</strong>}.</pre><p>That spec might be a bit too crowded, let’s unpack it:</p><p>This is the spec of a function called <em>if_not_empty, </em>with 2 arguments of types <strong>FunctionType</strong> and <strong>ListType</strong>, respectively. It can return elements of one of two possible types: <strong>ErrorType</strong> or <strong>OkType.</strong></p><p>Elements of type <strong>FunctionType </strong>are functions that receive a non-empty list of elements of type <strong>AnyType</strong> (<strong>[AnyType,…]</strong>) and return an element of another type (<strong>AnotherType</strong>).</p><p><strong>ListType</strong>, in turn, is a possibly empty list of elements of type <strong>AnyType</strong> (<strong>[AnyType]</strong>).</p><p>The result of a function is either <strong>ErrorType</strong> (that is the tuple <strong>{error, empty}</strong>) or <strong>OKType</strong> (a tuple of type <strong>{ok, AnotherType}</strong>, as in <strong>AnotherType</strong>, the result of the application of <strong>FunctionType</strong>).</p><p>It’s safe to assume that <em>if_not_empty/2</em> will return <strong>{error, empty} </strong>if the list it receives is empty and <strong>{ok, Function(List)}</strong> otherwise.</p><h3>Initial Solution</h3><p>Faced with that specification, developers (particularly folks coming from an object-oriented background) tend to implement their solution like this…</p><pre>if_not_empty(<strong>Function</strong>, <strong>List</strong>) -&gt;<br>    <em>if</em> length(<strong>List</strong>) &gt; <strong>0</strong> <em>-&gt;</em><br>           {ok, <strong>Function</strong>(<strong>List</strong>)};<br>       <em>true -&gt;</em><br>           {error, empty}<br>    <em>end</em>.</pre><p>It’s a correct solution, but not the most elegant nor the most performant one.</p><p>Before we tackle the performance issue, let’s deal with that nasty nasty <strong><em>if…</em></strong></p><h3>Without If</h3><p>As I’ve said in the past, in Erlang (and sometimes, in general) <a href="https://github.com/inaka/erlang_guidelines#avoid-if-statement">it is better to stay away from the if statement</a>. So, I generally recommend changing that code and (following <a href="https://github.com/inaka/erlang_guidelines#more-smaller-functions-over-case-expressions">another guideline</a>) use function clauses, instead.</p><p>That generally ends up in something similar to…</p><pre>if_not_empty(<strong>Function</strong>, <strong>List</strong>) when length(<strong>List</strong>) &gt; 0 -&gt;<br>    {ok, <strong>Function</strong>(<strong>List</strong>)};<br>if_not_empty(_, _) -&gt;<br>    {error, empty}.</pre><p>Much better! We’re almost there. But, let’s tackle the performance issue: Let’s benchmark this code in a totally unscientific way, just for the sake of exemplifying the situation…</p><pre><strong><em>% First, let&#39;s create a really long list…</em></strong><br>9&gt; LongList = [rand:uniform() || _ &lt;- lists:seq(1, 100000)].<br>[0.420515222637019,0.8779006956486717,0.8478602700250025,<br> 0.1570291508306687,0.9922807451124196,0.7020290584226024,<br> 0.22356701178759975,0.5231326543184913,0.8368749225021561,<br> 0.6239065648187836,0.4439549897507573,0.7351771695343225,<br> 0.5519649363326614,0.049439759267886574,0.7885233763802781,<br> 0.3857834407777109,0.7297454606625307,0.5908430855802675,<br> 0.2654111104532171,0.7267499922471473,0.3542637164641538,<br> 0.8517958528371183,0.4310782304329325,0.6897478919755892,<br> 0.13163761878786606,0.01160366378331068,0.9391918781985158,<br> 0.9608111320278309,0.9974567206076438|...]</pre><pre><strong><em>% Then, a function that does nothing…</em></strong><br>10&gt; DoNothing = fun(_) -&gt; nothing end.<br>#Fun&lt;erl_eval.44.79398840&gt;</pre><pre><strong><em>% And then run some benchmarks…<br></em></strong>11&gt; timer:tc(s, if_not_empty, [DoNothing, LongList]).<br>{<strong>182</strong>,{ok,nothing}}<br>12&gt; timer:tc(s, if_not_empty, [DoNothing, LongList]).<br>{<strong>163</strong>,{ok,nothing}}<br>13&gt; timer:tc(s, if_not_empty, [DoNothing, LongList]).<br>{<strong>208</strong>,{ok,nothing}}<br>14&gt; timer:tc(s, if_not_empty, [DoNothing, LongList]).<br>{<strong>232</strong>,{ok,nothing}}<br>15&gt; timer:tc(s, if_not_empty, [DoNothing, LongList]).<br>{<strong>190</strong>,{ok,nothing}}</pre><h3>Perfection</h3><p>At this point, I generally tell the developer three things:</p><ol><li>You’re not using the whole power of <strong>pattern-matching</strong></li><li>Even when <strong>length/1</strong> is written in C, the code still traverses the whole list to compute it.</li><li>You should use <strong><em>the robot butt!</em></strong></li></ol><p>And what is <strong>the robot butt</strong>?</p><p><em>Well… </em><strong><em>This</em></strong><em> is the </em><strong><em>robot butt</em></strong><em>…</em></p><pre>if_not_empty(Function, <strong>[_|_]</strong> = List) -&gt;<br>    {ok, Function(List)};<br>if_not_empty(_, _) -&gt;<br>    {error, empty}.</pre><p>That expression (<strong>[_|_]</strong>) will match on any non-empty list because it’s matching on a list with a head and a tail. They’re both disregarded since we used underscores (<strong>_</strong>)<strong> </strong>in their positions, but they <strong>must exist</strong>. And therefore, if the list has a head, it can not be empty.</p><p>And you can bet that this implementation is faster than the previous one…</p><pre>19&gt; timer:tc(s, if_not_empty, [DoNothing, LongList]).<br>{<strong>4</strong>,{ok,nothing}}<br>20&gt; timer:tc(s, if_not_empty, [DoNothing, LongList]).<br>{<strong>4</strong>,{ok,nothing}}<br>21&gt; timer:tc(s, if_not_empty, [DoNothing, LongList]).<br>{<strong>9</strong>,{ok,nothing}}<br>22&gt; timer:tc(s, if_not_empty, [DoNothing, LongList]).<br>{<strong>5</strong>,{ok,nothing}}<br>23&gt; timer:tc(s, if_not_empty, [DoNothing, LongList]).<br>{<strong>3</strong>,{ok,nothing}}</pre><p>So, next time you need to match on a non-empty list, remember to use the robot butt instead of checking its length. 🧐</p><p>Of course, you can also reverse the function clause order and match with an empty list in the first clause… but where is the fun in that? 😜</p><p>As a matter of fact, if you run this code through <a href="http://hex.pm/packages/rebar3_format">the formatter</a>, it will promptly tell you that it should be written as…</p><pre>if_not_empty(Function, <strong>[_ | _]</strong> = List) -&gt;<br>    {ok, Function(List)};<br>if_not_empty(_, _) -&gt;<br>    {error, empty}.</pre><p>Because, of course…</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/480/1*-Ra6YeExQL-qtpd-HtUN3w.gif" /><figcaption><a href="https://www.youtube.com/watch?v=wKfMZOR8eWI">Thank you, Sir MixALot. <strong>Thank you very much!</strong></a></figcaption></figure><p>Oh, and don’t forget to register for the upcoming 2021 edition of <a href="https://spawnfest.org/">Spawnfest</a>, organized by <strong><em>The Fellowship of the BEAM!</em></strong></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=bbd69e69beb2" width="1" height="1" alt=""><hr><p><a href="https://medium.com/erlang-battleground/ode-to-the-robot-butt-bbd69e69beb2">Ode to the Robot Butt</a> was originally published in <a href="https://medium.com/erlang-battleground">Erlang Battleground</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Simple TDD in Erlang]]></title>
            <link>https://medium.com/erlang-battleground/simple-tdd-in-erlang-5c0cca886acb?source=rss-788b9596f013------2</link>
            <guid isPermaLink="false">https://medium.com/p/5c0cca886acb</guid>
            <category><![CDATA[erlang]]></category>
            <category><![CDATA[test-driven-development]]></category>
            <dc:creator><![CDATA[Brujo Benavides]]></dc:creator>
            <pubDate>Fri, 08 May 2020 21:31:35 GMT</pubDate>
            <atom:updated>2020-05-08T21:31:35.857Z</atom:updated>
            <content:encoded><![CDATA[<h4>Or how to use Pattern-Matching for Tests</h4><p>While acting as a mentor on the <a href="https://www.futurelearn.com/courses/functional-programming-erlang/">FutureLearn MOOC about Erlang</a> I presented an idea that folks like <a href="https://medium.com/u/46e994019ae5">Adolfo Neto</a> loved (<a href="https://twitter.com/adolfont/status/1258852297964208130">he even tweeted about it</a> 🧡). It is, in fact, the way I introduce people to pattern-matching when I’m teaching them Erlang. It’s a way to write tests that let you naturally work your code out from them… Sounds familiar? Yes! <strong>It’s Test-Driven Development!</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*N6AkNTd9MvMiRXtkYJuxVQ.jpeg" /><figcaption>Airplane! (1980)</figcaption></figure><h3>The Process</h3><p>I learned TDD when I learned Smalltalk. It was such a life-changing lesson! And Smalltalk was the best environment to learn it since it’s built for it. In Smalltalk, I believe it’s actually harder to write code with a different process. If you didn’t try it already, you definitely should! Follow <a href="https://medium.com/u/8eea71cbc92">Hernan Wilkinson</a>, his company (10pines) delivers Smalltalk courses where you can learn this from the experts, among several other great things.</p><p>Anyway, for the uninitiated, the general process for TDD is…</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/606/1*tr-UVPcFhjlMUl4jLDG9Bw.png" /><figcaption><a href="https://images.xenonstack.com/blog/test-driven-development-process-cycle.png">Original Here</a></figcaption></figure><p>What’s not described in the graph (particularly for compiled languages, like Erlang) is that after adding a test, in order to <em>see that test fail</em>, you first need the code to <em>compile</em>. And that, at first hand, may seem difficult. But it’s actually possible, using a nice hot-code-loading related feature of Erlang.</p><p>Let’s dive in with an example…</p><h3>Do we have an extra day?</h3><p>So, let’s say you have to write a module year with a single function: is_leap/1 . As you might guess, the idea is for that function to receive an integer and return a boolean telling you if it’s a leap year or not.</p><h4>Add Tests</h4><p>For the first step, we will already use the magic trick I mentioned above. Look at the module we’ll write…</p><pre>-module year.<br>-export [test/0].</pre><pre>test() -&gt;<br>  false = <strong>year</strong>:<strong>is_leap</strong>(1),<br>  ok.</pre><p>Let’s dissect this thing…</p><p>The first two lines should be pretty obvious. We define the module and export test/0, which is the function we’ll use to run the tests.</p><p>Then we write the test/0 function. That function will just contain a series of assertions like most test functions do, specifying the expected results of our function is_leap/1.</p><p>The first assertion says that 1 is not a leap year. But pay attention to the fact that even when we’re going to eventually define is_leap/1 in this same module, we’re using the fully-qualified version of it (year:is_leap(…)) instead of just writing is_leap(1). Why? Hot-Code Reloading, <em>of course</em>!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/1*KQbWBBby45iDrtNdwj1pWg.gif" /><figcaption>Ron Damón as confused as you</figcaption></figure><p>The Erlang compiler will fail if it finds a call to an internal function that is not defined, it won’t compile your module and therefore it won’t run the test. <em>Except</em>… if you use a fully-qualified call. Because <a href="https://erlang.org/doc/reference_manual/code_loading.html#code-replacement">thanks to the logic behind hot code loading</a>, you can totally define that function <em>in a later version of the module.</em></p><p>That is super-useful for us since now we can…</p><h4>See Tests Fail</h4><pre>1&gt; c(year).<br>{ok, year}<br>2&gt; year:test().<br>** exception error: <strong>undefined function year:is_leap/1</strong><br>     in function  year:test/0 (year.erl, line 5)</pre><h4>Write Code</h4><p>Great! Now our test tells us that we need to define is_leap/1 … So we do!</p><pre>-module year.<br>-export [test/0].<br><strong>-export [is_leap/1].</strong></pre><pre>test() -&gt;<br>  false = year:is_leap(1),<br>  ok.</pre><pre><strong>is_leap(_) -&gt; false.</strong></pre><h4>Run Tests</h4><p>We try compiling and running our tests in a more succinct way so we can use up arrow each time we go to the console… oh, lazy lazy developers!</p><pre>3&gt; c(year), year:test().<br>ok.</pre><h4>Rinse and Repeat…</h4><p>Well… this is good! Now let’s add more assertions to our tests…</p><pre>-module year.<br>-export [test/0].<br>-export [is_leap/1].</pre><pre>test() -&gt;<br><strong>  % regular years are not leap<br></strong>  false = year:is_leap(1),<br><strong>  false = year:is_leap(1995),<br>  false = year:is_leap(1997),<br>  % multiples of 4 are leap…<br>  true = year:is_leap(1996),<br>  true = year:is_leap(2004),<br>  true = year:is_leap(2008),<br>  % …except if they&#39;re multiples of 100…<br>  false = year:is_leap(1800),<br>  false = year:is_leap(1900),<br>  false = year:is_leap(2100),<br>  % …except if they&#39;re also multiples of 400…<br>  true = year:is_leap(1600),<br>  true = year:is_leap(2000),<br>  true = year:is_leap(2400),</strong><br>  ok.</pre><pre>is_leap(_) -&gt; false.</pre><p>…aaand…</p><pre>5&gt; c(year), year:test().<br>** exception error: no match of right hand side value false<br>     in function  year:test/0 (year.erl, <strong>line 11</strong>)</pre><p>Line 11 is the one for 1996 (as expected)… We now fix our code for that case, run the tests again… Many iterations go by… etc…</p><p>I’ll jump to the final version for brevity…</p><pre>-module year.<br>-export [test/0].<br>-export [is_leap/1].</pre><pre>test() -&gt;<br>  % regular years are not leap<br>  false = year:is_leap(1),<br>  false = year:is_leap(1995),<br>  false = year:is_leap(1997),<br>  % multiples of 4 are leap…<br>  true = year:is_leap(1996),<br>  true = year:is_leap(2004),<br>  true = year:is_leap(2008),<br>  % …except if they&#39;re multiples of 100…<br>  false = year:is_leap(1800),<br>  false = year:is_leap(1900),<br>  false = year:is_leap(2100),<br>  % …except if they&#39;re also multiples of 400…<br>  true = year:is_leap(1600),<br>  true = year:is_leap(2000),<br>  true = year:is_leap(2400),<br>  ok.</pre><pre><strong>is_leap(Year) -&gt;<br>  is_leap(Year rem 4, Year rem 100, Year rem 400).</strong></pre><pre><strong>is_leap(_, _, 0) -&gt; true;<br>is_leap(_, 0, _) -&gt; false;<br>is_leap(0, _, _) -&gt; true;<br>is_leap(_, _, _) -&gt; false.</strong></pre><p>et voilà…</p><pre>7&gt; c(year), year:test().<br>ok</pre><h3>More Complex Stuff</h3><p>Of course, this technique only works for very small pieces of code that should not reach production. You don’t want that test code messing up your releases!</p><p>But if you choose <a href="https://erlang.org/doc/man/common_test.html">Common Test</a> as your testing framework, a suite for this module will look eerily familiar…</p><pre>-module year_SUITE.</pre><pre>-export [all/0].<br>-export [is_leap/1].</pre><pre>all() -&gt; [is_leap].</pre><pre>is_leap(_) -&gt;<br>  % regular years are not leap<br>  false = year:is_leap(1),<br>  false = year:is_leap(1995),<br>  false = year:is_leap(1997),<br>  % multiples of 4 are leap…<br>  true = year:is_leap(1996),<br>  true = year:is_leap(2004),<br>  true = year:is_leap(2008),<br>  % …except if they&#39;re multiples of 100…<br>  false = year:is_leap(1800),<br>  false = year:is_leap(1900),<br>  false = year:is_leap(2100),<br>  % …except if they&#39;re also multiples of 400…<br>  true = year:is_leap(1600),<br>  true = year:is_leap(2000),<br>  true = year:is_leap(2400),<br>  {comment, &quot;&quot;}.</pre><p>What do you think? Did I convince you to use Test-Driven Development for Erlang? 😉</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5c0cca886acb" width="1" height="1" alt=""><hr><p><a href="https://medium.com/erlang-battleground/simple-tdd-in-erlang-5c0cca886acb">Simple TDD in Erlang</a> was originally published in <a href="https://medium.com/erlang-battleground">Erlang Battleground</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Are formatters better than linters?]]></title>
            <link>https://elbrujohalcon.medium.com/are-formatters-better-than-linters-cbab91189be3?source=rss-788b9596f013------2</link>
            <guid isPermaLink="false">https://medium.com/p/cbab91189be3</guid>
            <category><![CDATA[code]]></category>
            <category><![CDATA[erlang]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[formatter]]></category>
            <dc:creator><![CDATA[Brujo Benavides]]></dc:creator>
            <pubDate>Fri, 03 Apr 2020 09:35:53 GMT</pubDate>
            <atom:updated>2020-04-03T09:35:53.896Z</atom:updated>
            <content:encoded><![CDATA[<p>So, I just watched <a href="https://medium.com/u/26903735cc30">Michał Muskała</a>’s talk at CodeBEAMSF, and I have something to say…</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FTC2F2HBNRuA%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DTC2F2HBNRuA&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FTC2F2HBNRuA%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/111e462a24f172ad0b245a48d12b0a27/href">https://medium.com/media/111e462a24f172ad0b245a48d12b0a27/href</a></iframe><p>As you might know, I’m also working with <a href="https://medium.com/u/d33c819bc49e">Juan Bono</a>, <a href="https://medium.com/u/42242c060db0">Diego Calero</a>, <a href="https://medium.com/u/f89b781338d4">Facundo Olano</a>, and others on <a href="http://tech.nextroll.com/blog/dev/2020/02/25/erlang-rebar3-format.html">our own formatter</a> for Erlang (just like Daniel Tipping is working on <a href="https://elixirforum.com/t/steamroller-an-opinionated-erlang-code-formatter/27532">steamroller</a>). I could write an article on how our formatter differs from <a href="https://medium.com/u/26903735cc30">Michał</a>’s but this time I want to focus our attention on a different topic.</p><p>Particularly I want to look at the following slide…</p><figure><img alt="Formatter &gt; Linter" src="https://cdn-images-1.medium.com/max/765/1*JK5ELp1xDBIVkEPaXHQqog.png" /><figcaption>Formatters are <em>more than Linters</em></figcaption></figure><h3>Are Formatters “Linters on Steroids”?</h3><p><a href="https://medium.com/u/26903735cc30">Michał</a> presents a concept in his talk that is somewhat widespread and I don’t think it’s correct: The idea that <em>if linters can tell you where you need to improve your code, formatters are better because they can </em><strong><em>just fix it.</em></strong></p><p>Having worked on both <a href="https://github.com/inaka/elvis/">Elvis</a> (a linter) and <a href="https://github.com/AdRoll/rebar3_format/">rebar3_format</a> (a formatter), I do believe that they are complementary but independent tools. They do have some intersection, but the really interesting parts are the ones where they don’t intersect with each other. And I believe this happens as well in other languages, for instance with <em>Credo</em> and <em>mix format</em> for Elixir.</p><p>There are things that linters can detect, but formatters can’t fix. To name a few Elvis rules like that:</p><ul><li><a href="https://github.com/inaka/elvis_core/wiki/Rules#nesting-level"><strong>Nesting Level</strong></a><strong>:</strong> The linter can detect that your code is nested too deeply, but what will the formatter do to fix that? It could theoretically <em>move some lines out to a different function </em>but I don’t think that’s something you would expect your formatter to do, right?</li><li><a href="https://github.com/inaka/elvis_core/wiki/Rules#no-debug-call"><strong>No debug calls</strong></a><strong>: </strong>The linter can tell you that you left some io:format’s in your production code, which is not good. I don’t think the formatter should <em>just</em> <em>remove them</em>. Leaving aside the fact that sometimes it’s not <em>as easy</em> as <em>just</em> removing the calls.</li><li><a href="https://github.com/inaka/elvis_core/wiki/Rules#dry"><strong>DRY</strong></a><strong>: </strong>My favorite Elvis rule of all time: The linter can identify pieces of code that are repeated. What will the formatter do here? A tool that would actually refactor your code to extract them to a separate function would be amazing but I don’t think the formatter should be that tool.</li></ul><p>If only we had a tool to automatically perform all those tasks… Maybe <a href="https://medium.com/u/d3131b7e893f">SimonThompson</a> <a href="https://www.cs.kent.ac.uk/projects/wrangler/Wrangler/Home.html">knows one</a>? 🙄</p><p>On the other hand, there are things that a formatter can fix and a linter shouldn’t deal with, like:</p><ul><li><strong>Consistent indentation of clauses. </strong>The linter can warn you on whether you’re using tabs or spaces for indentation but figuring out if you properly indented all your code using the right number of spaces/tabs is not worth the effort, particularly if you have a tool like a formatter that <em>just fixes that for you</em>.</li><li><strong>Personalization. </strong>As I mentioned in <a href="http://tech.nextroll.com/blog/dev/2020/02/25/erlang-rebar3-format.html">my article</a> linked above, I believe that formatters should have room for personalization, so I can read the code in the way I understand it best and you can read the same code in the way that <em>you</em> like it best. We don’t need to fight over comma-first ROK-style, indentation levels, tabs-vs-spaces… As long as we share a format for the code once its pushed, each one of us can work using his/her own style. That’s something that the linter can’t allow since the idea is that the rules enforced by the linter are respected by all of us.</li></ul><h3>Conclusion</h3><p>The linter and the formatter are different tools that serve different purposes. The linter will make sure your code is <strong>well written</strong> and follows the <strong>best practices</strong> defined by the community or your team. The formatter will make sure that your code is <strong>nicely written </strong>and <strong>easy to understand</strong> by any other developer.</p><p>A formatter will happily make some linter rules <strong>obsolete</strong> (which is great!) but it won’t remove the need for it, at all.</p><p>In other words…</p><blockquote>Don’t stop using a linter when you start using a formatter!</blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=cbab91189be3" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Comprehend Comprehensions]]></title>
            <link>https://medium.com/erlang-battleground/how-to-comprehend-comprehensions-c924f92a97e1?source=rss-788b9596f013------2</link>
            <guid isPermaLink="false">https://medium.com/p/c924f92a97e1</guid>
            <category><![CDATA[functional-programming]]></category>
            <category><![CDATA[erlang]]></category>
            <dc:creator><![CDATA[Brujo Benavides]]></dc:creator>
            <pubDate>Fri, 23 Aug 2019 14:07:30 GMT</pubDate>
            <atom:updated>2019-08-23T14:07:30.667Z</atom:updated>
            <content:encoded><![CDATA[<h4>Particularly for Erlang</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*UGxEBcAHZkcIszrF-crUww.jpeg" /><figcaption>Good Will Hunting (1997)</figcaption></figure><p>So, <a href="https://medium.com/u/afb22da57efa">I Gusti Ngurah Oka Prinarjaya</a> was reading <a href="https://gangrel.files.wordpress.com/2015/08/programming-erlang-2nd-edition.pdf">Joe’s Book</a> and he found one of the most amazing examples of List Comprehensions I’ve ever seen…</p><pre>perms([]) -&gt; [[]];<br>perms(List) -&gt; [ [H|T] || H &lt;- List, T &lt;- perms(List--[H]) ].</pre><h4>Output:</h4><pre>1&gt; lib_misc:perms(&quot;123&quot;).<br>[&quot;123&quot;,&quot;132&quot;,&quot;213&quot;,&quot;231&quot;,&quot;312&quot;,&quot;321&quot;]</pre><p>And, of course… he couldn’t understand it. And, as a seasoned Erlang trainer, I got to tell you: He’s not alone… by any means. After a session of the <a href="https://www.meetup.com/BeamBA">BeamBA Meetup</a> where I casually tried to explain something even simpler than this, we had to schedule <a href="https://www.meetup.com/BeamBA/events/255305278/">another meetup talk</a> just to explain <em>how recursion works</em> and<em> how to think recursively.</em></p><p>So, let me try to explain how recursion and list comprehensions work together in <em>perms/1</em>, how can one end up with a function like that and how to read it. Let’s see how far I can get in a blog post… and <a href="https://medium.com/u/68e3df6c3d43">Robert Virding</a> (I know you’re a fan of <em>perms/1</em>) please point out the mistakes I’ll surely make ;)</p><h3>How to write a function like that?</h3><p>So, let’s first think of how will we come up with such a beautiful function.</p><p>The requirement here is pretty simple:</p><blockquote>The function <strong>perms/1</strong> should receive a single argument (a list) and return the list of all possible permutations of it.</blockquote><p>To understand what it does, let’s write a test for it, shall we? (I’ll use strings, since that’s what Joe used in his book, but any list will do)</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c211b05b6e5956b7f69b1dab0005162b/href">https://medium.com/media/c211b05b6e5956b7f69b1dab0005162b/href</a></iframe><p>Cool, if we try to run that test it will tell us that we need to implement the function…</p><pre>1&gt; c(joe), joe:test().<br>** exception error: undefined function joe:perms/1<br>     in function  joe:test/0 (joe.erl, line 6)<br>2&gt;</pre><p>We can start with the base case then… The only permutation of an empty list is itself.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2e29c2000e6f571c38bcba3ed5ee5970/href">https://medium.com/media/2e29c2000e6f571c38bcba3ed5ee5970/href</a></iframe><p>That moved us one step ahead. Cool!</p><pre>2&gt; c(joe), joe:test().<br>** exception error: no function clause matching joe:perms(&quot;a&quot;) (joe.erl, line 13)<br>     in function  joe:test/0 (joe.erl, line 7)<br>3&gt;</pre><p>Now, for the recursive step…</p><p>When writing recursive functions, we must assume that we know how to apply the function to a <em>smaller</em> input. In our case, we’re working with lists, so <em>a smaller input</em> can be the tail of the list (since it’s a smaller list). That’s why my first step when writing this code would be something like this…</p><pre>perms([H|T]) -&gt; … perms(T) ….</pre><p>In other words, I take the head of the list (H) and apply the function recursively to its tail (T). Now we have to figure out how to move from <em>the list of permutations for </em><em>T </em>to <em>the list of permutations for </em><em>[H|T] .</em></p><p>So, let’s say H=a, T=[b,c], then perms(T) == [[b,c], [c,b]] and we want to get to [[a,b,c], [a,c,b], [b,a,c], [c,a,b], [b,c,a], [c,b,a]]. 🤔</p><p>The first two are easy to build: [ [H|P] || P &lt;- perms(T) ]. So far, so good. Let’s try it and see what the tests have to say about it.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2a2cba71e4e164e0210df249a1a3974c/href">https://medium.com/media/2a2cba71e4e164e0210df249a1a3974c/href</a></iframe><pre>3&gt; c(joe), joe:test().<br>** exception error: no match of right hand side value [&quot;ab&quot;]<br>     in function  joe:test/0 (joe.erl, line 8)<br>4&gt;</pre><p>Right… perms(&quot;ab&quot;) is not equal to [&quot;ab&quot;, &quot;ba&quot;] , it’s just [&quot;ab&quot;]. We’re just adding the permutations that have the elements <em>in order</em>, since we’re traversing the list from left to right. We need a different way to <em>reduce</em> our list.</p><p>So far we had perms(T) be the list of permutations of the elements in the tail of the list. What if we had access to the list of <em>all permutations</em> of any sublist of the original list ([H|T]) with one element less (i.e. what if for [a,b,c] we could build the list of all permutations for [a,b], the list of all permutations for [b,c], and the one for [a,c]). In that case, to build the final result we will only need to add the missing element to their heads.</p><p>Too complex? Well… let’s go step by step… First let’s build all the sublists…</p><pre>perms(List) -&gt; [List -- [H] || H &lt;- List].</pre><p>Let’s test that on the shell for a second…</p><pre>4&gt; c(joe), joe:perms(&quot;ab&quot;).<br>[&quot;b&quot;,&quot;a&quot;]<br>5&gt; c(joe), joe:perms(&quot;abc&quot;).<br>[&quot;bc&quot;,&quot;ac&quot;,&quot;ab&quot;]<br>6&gt; c(joe), joe:perms(&quot;abcd&quot;).<br>[&quot;bcd&quot;,&quot;acd&quot;,&quot;abd&quot;,&quot;abc&quot;]<br>7&gt;</pre><p>Nice! So… this following code won’t work, but if we could compute the permutations for each of those sublists like this…</p><pre>perms(List) -&gt; [perms(List -- [H]) || H &lt;- List].</pre><p>…we would end up with something like…</p><pre>4&gt; c(joe), joe:perms(&quot;ab&quot;).<br>[[&quot;b&quot;],[&quot;a&quot;]]<br>5&gt; c(joe), joe:perms(&quot;abc&quot;).<br>[[&quot;bc&quot;,&quot;cb&quot;], [&quot;ac&quot;,&quot;ca&quot;], [&quot;ab&quot;,&quot;ba&quot;]]<br>6&gt;</pre><p>Let me first apply a neat trick here to <em>flatten </em>the list. Something we can easily do in List Comprehensions by just using multiple generators.</p><pre>perms(List) -&gt; [T || H &lt;- List, T &lt;- perms(List -- [H])].</pre><p>Again, using a built-up example since the code won’t actually work like this…</p><pre>4&gt; c(joe), joe:perms(&quot;ab&quot;).<br>[&quot;b&quot;,&quot;a&quot;]<br>5&gt; c(joe), joe:perms(&quot;abc&quot;).<br>[&quot;bc&quot;,&quot;cb&quot;, &quot;ac&quot;,&quot;ca&quot;, &quot;ab&quot;,&quot;ba&quot;]<br>6&gt;</pre><p>We’re really close there. To get from [&quot;b&quot;,&quot;a&quot;] to the actual result we want ([&quot;ab&quot;, &quot;ba&quot;]) we just need to prepend each list with the element we originally removed (which is H in our code). Let’s try that!</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/48d38dd63df6e32e70a49f00d780327f/href">https://medium.com/media/48d38dd63df6e32e70a49f00d780327f/href</a></iframe><pre>7&gt; c(joe), joe:test().<br>ok<br>8&gt;</pre><p>Well… that’s Joe’s code, isn’t it? What did you expect? 😉</p><h3>How to read a function like that?</h3><p>Well, that was fun, but what if you are faced with a function like that and your job is to <em>understand</em> it, not to write it. Well, a neat technique you can use it to compute the reductions <em>manually</em> or using the debugger. I’ll do it manually here.</p><p>What we’ll be doing is basically emulating the VM work by hand, one step at a time. So, let’s start with a sample expression and let’s see what the VM would do. To be clear: these are not the <em>actual</em> reductions in the VM. I took some liberties, mostly because LCs are just syntactic sugar. But I hope you understand what I’m showing here…</p><pre>perms(&quot;123&quot;).<br><strong>% Second clause of perms/1</strong><br>[ [H|T] || H &lt;- &quot;123&quot;, T &lt;- joe:perms(&quot;123&quot; -- [H])].<br><strong>% Expansion of the first generator</strong><br>[ [$1|T] || T &lt;- joe:perms(&quot;123&quot; -- &quot;1&quot;) ] ++<br>[ [$2|T] || T &lt;- joe:perms(&quot;123&quot; -- &quot;2&quot;) ] ++<br>[ [$3|T] || T &lt;- joe:perms(&quot;123&quot; -- &quot;3&quot;) ].<br><strong>% Reduction of --</strong><br>[ [$1|T] || T &lt;- joe:perms(&quot;23&quot;) ] ++<br>[ [$2|T] || T &lt;- joe:perms(&quot;13&quot;) ] ++<br>[ [$3|T] || T &lt;- joe:perms(&quot;12&quot;) ].<br><strong>% Multiple second clauses of perms/1</strong><br>[ [$1|T]<br>  || T &lt;- [ [H|T1] || H &lt;- &quot;23&quot;, T1 &lt;- joe:perms(&quot;23&quot; -- [H])]] ++<br>[ [$2|T]<br>  || T &lt;- [ [H|T1] || H &lt;- &quot;13&quot;, T1 &lt;- joe:perms(&quot;13&quot; -- [H])] ] ++<br>[ [$3|T]<br>  || T &lt;- [ [H|T1] || H &lt;- &quot;12&quot;, T1 &lt;- joe:perms(&quot;12&quot; -- [H])] ].<br><strong>% Multiple expansion of first generators and --</strong><br>[ [$1|T]<br>  || T &lt;- [ [$2|T1] || T1 &lt;- joe:perms(&quot;3&quot;)] ++<br>          [ [$3|T1] || T1 &lt;- joe:perms(&quot;2&quot;)] ] ++<br>[ [$2|T]<br>  || T &lt;- [ [$1|T1] || T1 &lt;- joe:perms(&quot;3&quot;)] ++<br>          [ [$3|T1] || T1 &lt;- joe:perms(&quot;1&quot;)] ] ++<br>[ [$3|T]<br>  || T &lt;- [ [$1|T1] || T1 &lt;- joe:perms(&quot;2&quot;)] ++<br>          [ [$2|T1] || T1 &lt;- joe:perms(&quot;1&quot;)] ].</pre><p>Let’s work on perms(“3”) alone for a second…</p><pre>perms(&quot;3&quot;).<br><strong>% Second clause of perms/1</strong><br>[ [H|T] || H &lt;- &quot;3&quot;, T &lt;- joe:perms(&quot;3&quot; -- [H])].<br><strong>% Expansion of the first generator</strong><br>[ [$3|T] || T &lt;- joe:perms(&quot;3&quot; -- &quot;3&quot;)].<br><strong>% Reduction of --</strong><br>[ [$3|T] || T &lt;- joe:perms(&quot;&quot;)].<br><strong>% First clause of perms/1</strong><br>[ [$3|T] || T &lt;- [[]]].<br><strong>% Expansion of the generator</strong><br>[ [$3|[]] ].<br><strong>% List reduction (and some syntax sugar)</strong><br>[&quot;3&quot;].</pre><p>And you can work with the other small lists in an analogous manner. So, going back to the original example…</p><pre><strong>% Multiple expansion of all simple perm/1&#39;s</strong><br>[ [$1|T]<br>  || T &lt;- [ [$2|T1] || T1 &lt;- [&quot;3&quot;]] ++<br>          [ [$3|T1] || T1 &lt;- [&quot;2&quot;]] ] ++<br>[ [$2|T]<br>  || T &lt;- [ [$1|T1] || T1 &lt;- [&quot;3&quot;]] ++<br>          [ [$3|T1] || T1 &lt;- [&quot;1&quot;]] ] ++<br>[ [$3|T]<br>  || T &lt;- [ [$1|T1] || T1 &lt;- [&quot;2&quot;]] ++<br>          [ [$2|T1] || T1 &lt;- [&quot;1&quot;]] ].<br><strong>% Expansion of all simple generators</strong><br>[ [$1|T] || T &lt;- [[$2|&quot;3&quot;]] ++ [[$3|&quot;2&quot;]] ] ++<br>[ [$2|T] || T &lt;- [[$1|&quot;3&quot;]] ++ [[$3|&quot;1&quot;]] ] ++<br>[ [$3|T] || T &lt;- [[$1|&quot;2&quot;]] ++ [[$2|&quot;1&quot;]] ].<br><strong>% Reduction of cons operator</strong><br>[ [$1|T] || T &lt;- [&quot;23&quot;] ++ [&quot;32&quot;] ] ++<br>[ [$2|T] || T &lt;- [&quot;13&quot;] ++ [&quot;31&quot;] ] ++<br>[ [$3|T] || T &lt;- [&quot;12&quot;] ++ [&quot;21&quot;] ].<br><strong>% Reduction of ++</strong><br>[ [$1|T] || T &lt;- [&quot;23&quot;, &quot;32&quot;] ] ++<br>[ [$2|T] || T &lt;- [&quot;13&quot;, &quot;31&quot;] ] ++<br>[ [$3|T] || T &lt;- [&quot;12&quot;, &quot;21&quot;] ].<br><strong>% Expansion of generators</strong><br>[[$1|&quot;23&quot;]] ++ [[$1|&quot;32&quot;]] ++<br>[[$2|&quot;13&quot;]] ++ [[$2|&quot;31&quot;]] ++<br>[[$3|&quot;12&quot;]] ++ [[$3|&quot;21&quot;]].<br><strong>% Reduction of ++ and cons</strong><br>[&quot;123&quot;, &quot;132&quot;, &quot;213&quot;, &quot;231&quot;, &quot;312&quot;, &quot;321&quot;].</pre><p>Et voilà! 🎉</p><p>What you see here is kind of the same algorithm I described above:</p><blockquote>For each element in the original list, find all the permutations for the sublist that results from removing it, then attach the element to the head of each permutation.</blockquote><p>It’s quite a simple algorithm to describe (and thus the resulting function is also quite simple and descriptive) but it might be hard to understand <em>how</em> such an algorithm actually solves the problem. I hope this article brings some light on the subject. 😃</p><h3>In Other News…</h3><h3>SpawnFest</h3><p><strong>We’re less than a month away from </strong><a href="https://spawnfest.github.io/"><strong><em>SpawnFest</em></strong></a><strong><em>!<br></em></strong>This year it will happen on <strong>September 21st &amp; 22nd.<br></strong><a href="https://spawnfest.github.io/#registration">Register your team</a> and join us <strong>for FREE</strong> to win several amazing prizes provided by our great sponsors!</p><h3>ElixirConfLA</h3><p><strong><em>ElixirConf</em> </strong>is coming to Latin America for the first time!<br>Thanks to our friends from <a href="https://playusmedia.com/">PlayUS Media</a>, we’ll meet in Medellín, Colombia for <a href="http://elixirconf.la/">ElixirConfLA</a> on <strong>October 24th &amp; 25th</strong>.<br>It will be an awesome event, you don’t want to miss it :)</p><h3>Erlang Battleground</h3><p>We’re still looking for writers. If you want to write on Erlang Battleground, just let us know! ✍️</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c924f92a97e1" width="1" height="1" alt=""><hr><p><a href="https://medium.com/erlang-battleground/how-to-comprehend-comprehensions-c924f92a97e1">How to Comprehend Comprehensions</a> was originally published in <a href="https://medium.com/erlang-battleground">Erlang Battleground</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>