<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<title></title>
	<link href="https://doma.dev/atom.xml" rel="self" type="application/atom+xml"/>
  <link href="https://doma.dev"/>
	<generator uri="https://www.getzola.org/">Zola</generator>
	<updated>2021-09-03T17:30:00+00:00</updated>
	<id>https://doma.dev/atom.xml</id>
	<entry xml:lang="en">
		<title>Type system innovation propagation</title>
		<published>2021-09-03T17:30:00+00:00</published>
		<updated>2021-09-03T17:30:00+00:00</updated>
		<link href="https://doma.dev/blog/innovation-propagation/" type="text/html"/>
		<id>https://doma.dev/blog/innovation-propagation/</id>
		<content type="html">&lt;h2 id=&quot;tl-dr&quot;&gt;TL;DR&lt;a class=&quot;zola-anchor&quot; href=&quot;#tl-dr&quot; aria-label=&quot;Anchor link for: tl-dr&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Incorporation of established programming language theory approaches is desired by mainstream language designers.
&lt;ul&gt;
&lt;li&gt;The fashion in which parametric polymorphism has enabled generics in Java and Go demonstrates this.&lt;&#x2F;li&gt;
&lt;li&gt;Go with generics has the potential to solve the expression problem.&lt;&#x2F;li&gt;
&lt;li&gt;C++ has got it right straight away and work has been done to improve parametric polymorphism to allow for ergonomic higher kinded types (generic types that themselves accept type variables).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Incorporation of PLT approaches can be unified and applied to many different compilers&lt;&#x2F;li&gt;
&lt;li&gt;Further work is required to further improve expressiveness and ergonomics of languages with type systems.
&lt;ul&gt;
&lt;li&gt;Most of languages with type systems lack scalable ways to deal with heterogenous data.&lt;&#x2F;li&gt;
&lt;li&gt;Structure-aware features and row polymorphism asks for a wider adoption than just in PureScript.&lt;&#x2F;li&gt;
&lt;li&gt;Lack of efficient structure-aware features algorithms holds back the adoption greatly.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;why-not-settle-for-naive-or-simple-type-systems&quot;&gt;Why not settle for naive or simple type systems?&lt;a class=&quot;zola-anchor&quot; href=&quot;#why-not-settle-for-naive-or-simple-type-systems&quot; aria-label=&quot;Anchor link for: why-not-settle-for-naive-or-simple-type-systems&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Most language designers agree that type systems should have first-class treatment in programming languages. Almost all the programming languages saw their type systems evolve to incorporate new features. In this post we&#x27;ll study some of such cases and motivate the need for furthering type system R&amp;amp;D beyond what we have now at our disposal.&lt;&#x2F;p&gt;
&lt;p&gt;To do that, we shall look at the history of two mainstream programming languages (Java and Go) through the lens of generic computing in said languages. In this post, when we talk about generic computing, we mean &amp;quot;ways to program in a type-agnostic way&amp;quot; or &amp;quot;writing a program that doesn&#x27;t just work on one concrete type, but works on some class of types&amp;quot;.&lt;&#x2F;p&gt;
&lt;p&gt;Thus, generic computing is instrumental even to the most basic programming. Data structures (trees, arrays, ...) are foundational to the discipline and intrinsically generic. The challenge then, is to encode them in a type-safe way. A motivational example would be Java&#x27;s &amp;quot;Hashtable&amp;quot;, as seen in version 1.0, dated 7th of January, 1998.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;razor-sharp-generic-computing&quot;&gt;Razor-sharp generic computing&lt;a class=&quot;zola-anchor&quot; href=&quot;#razor-sharp-generic-computing&quot; aria-label=&quot;Anchor link for: razor-sharp-generic-computing&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Consider &lt;code&gt;get&lt;&#x2F;code&gt; function from Java 1.0:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;Java 1.0 &quot;hashtable get&quot;&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-Java 1.0 &quot;hashtable get&quot; &quot;&gt;&lt;code class=&quot;language-Java 1.0 &quot;hashtable get&quot;&quot; data-lang=&quot;Java 1.0 &quot;hashtable get&quot;&quot;&gt;&lt;span&gt;public synchronized Object get(Object key) {
&lt;&#x2F;span&gt;&lt;span&gt;    HashtableEntry tab[] = table;
&lt;&#x2F;span&gt;&lt;span&gt;    int hash = key.hashCode();
&lt;&#x2F;span&gt;&lt;span&gt;    int index = (hash &amp;amp; 0x7FFFFFFF) % tab.length;
&lt;&#x2F;span&gt;&lt;span&gt;    for (HashtableEntry e = tab[index] ; e != null ; e = e.next) {
&lt;&#x2F;span&gt;&lt;span&gt;        if ((e.hash == hash) &amp;amp;&amp;amp; e.key.equals(key)) {
&lt;&#x2F;span&gt;&lt;span&gt;    	return e.value;
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;    return null;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Considerations for &lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=ybrQvs4x0Ps&quot;&gt;the billion dollar mistake&lt;&#x2F;a&gt; aside, when we talk about type safety of this snippet, we see that, on line three of it, we call method &lt;code&gt;hashCode()&lt;&#x2F;code&gt; of an instance of class &lt;code&gt;Object&lt;&#x2F;code&gt;. This approach to &amp;quot;generics&amp;quot; asks engineers to have a single point in the closed type hierarchy, which mandates all the necessary methods for the generic applications. This approach is a source of headache for library implementers. Even if we negotiate that using Interfaces is good enough for implementing generic programs (think, &lt;code&gt;get&lt;&#x2F;code&gt; would accept &lt;code&gt;IHashable&lt;&#x2F;code&gt; instead of &lt;code&gt;Object&lt;&#x2F;code&gt;), the problems still exist.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Upcasting (also known as generalisation, treatment of a subtype as a supertype) to an interface or an Object would result in the return value of a wider-than-needed type, which would require for downcasting (also known as specialisation, treatment of a supertype as a subtype) later on, throwing away type guarantees and creating a space for errors.&lt;&#x2F;li&gt;
&lt;li&gt;Less significantly, overlapping abstract method names in interfaces without resolving facilities make generic programming via upcasting less scalable.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The pioneering language in the modern type systems engineering, which gave raise to Haskell and Ocaml is called &amp;quot;ML&amp;quot;. ML, in mid-seventies, has introduced something called &amp;quot;parametric polymorphism&amp;quot;, the idea of which is to let programmers have variables for types themselves in a similar way that programmers have variables for values. Modern Java&#x27;s Hashtable uses parametric polymorphism and is said to be &amp;quot;polymorphic in key and value types&amp;quot;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;Modern class information of hashtable&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-Modern class information of hashtable &quot;&gt;&lt;code class=&quot;language-Modern class information of hashtable&quot; data-lang=&quot;Modern class information of hashtable&quot;&gt;&lt;span&gt;public class Hashtable&amp;lt;K,V&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;extends Dictionary&amp;lt;K,V&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;implements Map&amp;lt;K,V&amp;gt;, Cloneable, Serializable
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;case-study-type-variables-for-better-polymorphism&quot;&gt;Case study: type variables for better polymorphism&lt;a class=&quot;zola-anchor&quot; href=&quot;#case-study-type-variables-for-better-polymorphism&quot; aria-label=&quot;Anchor link for: case-study-type-variables-for-better-polymorphism&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;generic-java&quot;&gt;Generic Java&lt;a class=&quot;zola-anchor&quot; href=&quot;#generic-java&quot; aria-label=&quot;Anchor link for: generic-java&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;As we discussed, initial approach to generic programming in Java was to use Object, the common super-class for any Java class. &lt;a href=&quot;http:&#x2F;&#x2F;pizzacompiler.sourceforge.net&#x2F;&quot;&gt;Pizza language&lt;&#x2F;a&gt;, made by Odersky (eventually, the creator of Scala) and Wadler (co-designer of Haskell), released one year after Java, was a superset of Java that was a bit more principled and allowed for type variables that would then be &amp;quot;erased&amp;quot; and translated into Object class, automating upcasting and downcasting, thus retaining type safety. It also allows to remove the problem with exponential blow-up of compiled artefacts like the one seen in C++ due to conditional code generation. More on that later.&lt;&#x2F;p&gt;
&lt;p&gt;Type erasure is greatly misunderstood and some shortcomings of Java type system is misattributed to it, but it&#x27;s not without its drawbacks. Most notably, one cannot use type variables in Java in to cast values to that type. I.e. &lt;code&gt;(T)x&lt;&#x2F;code&gt; is not a valid expression if T is type variable. The other drawback of type erasure is that even if a generic data structure or method is parametrised with a primitive type, the overhead of boxing it (turning it into a Java class) will be carried via erasure. Note that none of the drawbacks of type erasure limit type safety, only expressiveness and performance.&lt;&#x2F;p&gt;
&lt;p&gt;Wadler et al., after Pizza was released, made a minimum viable formalisation of Java, which was instrumental for eventual inclusion of generics in Java in version 1.5, in 2004.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;generic-go&quot;&gt;Generic Go&lt;a class=&quot;zola-anchor&quot; href=&quot;#generic-go&quot; aria-label=&quot;Anchor link for: generic-go&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Go is infamous for the longest time between the release of an industrial language and getting generics. Importantly, it gave room for what I call &lt;code&gt;void *&lt;&#x2F;code&gt; polymorphism. In Go circa 2021, it&#x27;s &lt;code&gt;interface{}&lt;&#x2F;code&gt; polymorphism and, without going into much details about why it works, we&#x27;ll present you with real code that makes use of it:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;Runtime switching on type information in Go to convert a value of type &quot;empty interface&quot; to boolean&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-Runtime switching on type information in Go to convert a value of type &quot;empty interface&quot; to boolean &quot;&gt;&lt;code class=&quot;language-Runtime switching on type information in Go to convert a value of type &quot;empty interface&quot; to boolean&quot; data-lang=&quot;Runtime switching on type information in Go to convert a value of type &quot;empty interface&quot; to boolean&quot;&gt;&lt;span&gt;func ToBoolE(i interface{}) (bool, error) {
&lt;&#x2F;span&gt;&lt;span&gt;	i = indirect(i)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;	switch b := i.(type) {
&lt;&#x2F;span&gt;&lt;span&gt;	case bool:
&lt;&#x2F;span&gt;&lt;span&gt;		return b, nil
&lt;&#x2F;span&gt;&lt;span&gt;	case nil:
&lt;&#x2F;span&gt;&lt;span&gt;		return false, nil
&lt;&#x2F;span&gt;&lt;span&gt;	case int:
&lt;&#x2F;span&gt;&lt;span&gt;		if i.(int) != 0 {
&lt;&#x2F;span&gt;&lt;span&gt;			return true, nil
&lt;&#x2F;span&gt;&lt;span&gt;		}
&lt;&#x2F;span&gt;&lt;span&gt;		return false, nil
&lt;&#x2F;span&gt;&lt;span&gt;	case string:
&lt;&#x2F;span&gt;&lt;span&gt;		return strconv.ParseBool(i.(string))
&lt;&#x2F;span&gt;&lt;span&gt;	default:
&lt;&#x2F;span&gt;&lt;span&gt;		return false, fmt.Errorf(&amp;quot;unable to cast %#v of type %T to bool&amp;quot;, i, i)
&lt;&#x2F;span&gt;&lt;span&gt;	}
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is clearly problematic, because usage of &lt;code&gt;interface{}&lt;&#x2F;code&gt; type in programs poisons them with runtime switching over type information, unlifting the failure detection from the realm of static analysis to the realm of dynamic monitoring. Furthermore, a slight change in the acceptable types shall cause a refactoring hell! There would be no way to know, when you extend domain of your &lt;code&gt;interface{}&lt;&#x2F;code&gt; function, which other functions need to have their domain also extended.&lt;&#x2F;p&gt;
&lt;p&gt;Similarly to introducing generics to Java, introducing generics to Go included two stages: formalisation and implementation proposal. Given the experience of the team who is behind generics in Go experience in the matter (a lot of it is thanks to having Wadler on board), in case of Go, proper formalisation came first, it was implemented later.&lt;&#x2F;p&gt;
&lt;p&gt;Another reason for starting with formalisation first in case of Go, perhaps, is rooted in the fact that adding parametric polymorphism to Go is harder than doing so in Java. Indeed, one of the great features of Go language is that its struct-interface supertyping is open.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;demonstrating function Show that happens to be defined on a struct called Nil&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-demonstrating function Show that happens to be defined on a struct called Nil &quot;&gt;&lt;code class=&quot;language-demonstrating function Show that happens to be defined on a struct called Nil&quot; data-lang=&quot;demonstrating function Show that happens to be defined on a struct called Nil&quot;&gt;&lt;span&gt;package s
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;type Nil struct{}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;func (n *Nil)Show() string {
&lt;&#x2F;span&gt;&lt;span&gt;        return &amp;quot;{}&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;A structure with a function in a package defined independently can indeed happen to implement an interface defined in another package:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;which requires 0-ary function Show to be implemented for the objective struct&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-which requires 0-ary function Show to be implemented for the objective struct &quot;&gt;&lt;code class=&quot;language-which requires 0-ary function Show to be implemented for the objective struct&quot; data-lang=&quot;which requires 0-ary function Show to be implemented for the objective struct&quot;&gt;&lt;span&gt;package main
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;import (
&lt;&#x2F;span&gt;&lt;span&gt;        &amp;quot;fmt&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;        . &amp;quot;doma.dev&#x2F;s&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;type Shower interface {
&lt;&#x2F;span&gt;&lt;span&gt;        Show() string
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;func f(a Shower) string {
&lt;&#x2F;span&gt;&lt;span&gt;        return a.Show()
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;func main() {
&lt;&#x2F;span&gt;&lt;span&gt;        var x = Nil{}
&lt;&#x2F;span&gt;&lt;span&gt;        fmt.Println(f(&amp;amp;x))
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Further complication which warranted careful planning for this feature was that the goal was to use code generation (fancy word for which is &amp;quot;monomoprhisation&amp;quot; because poly-morphic things spawn a bunch of mono-morphic things), instead of type erasure, to achieve more versatile generics at the expense of binary size.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, &lt;a href=&quot;https:&#x2F;&#x2F;go.googlesource.com&#x2F;proposal&#x2F;+&#x2F;refs&#x2F;heads&#x2F;master&#x2F;design&#x2F;43651-type-parameters.md&quot;&gt;a proposal&lt;&#x2F;a&gt; that adds generics with constraints (which programmers can create and use in their code) was implemented. &lt;&#x2F;p&gt;
&lt;p&gt;An important outtake from this case study is that the same idea from programming language theory can be applied to completely different compilers following the same methodology!&lt;&#x2F;p&gt;
&lt;h3 id=&quot;go-and-expression-problem-test&quot;&gt;Go and expression problem test&lt;a class=&quot;zola-anchor&quot; href=&quot;#go-and-expression-problem-test&quot; aria-label=&quot;Anchor link for: go-and-expression-problem-test&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Besides, Generic Go, as currently implemented &lt;em&gt;almost&lt;&#x2F;em&gt; passes the expression problem test.&lt;&#x2F;p&gt;
&lt;p&gt;The expression problem, essentially, states that without changing the existing source code in modules (except for the integration module) and while preserving type safety, codebase is extendable with:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;a new type, implementing all existing functions;&lt;&#x2F;li&gt;
&lt;li&gt;a new function over all existing types.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The expression problem test is then formulated as follows:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Work with expressions for a calculator DSL that builds up arithmetic expressions and then evaluates them (hence the name of &amp;quot;expression problem&amp;quot;).&lt;&#x2F;li&gt;
&lt;li&gt;Start with an expression type case &amp;quot;constant&amp;quot; which holds a value of some primitive numeric type.&lt;&#x2F;li&gt;
&lt;li&gt;Implement a function &amp;quot;evaluate&amp;quot; that takes an expression and returns the corresponding value of the primitive numeric type.&lt;&#x2F;li&gt;
&lt;li&gt;Implement &amp;quot;evaluate&amp;quot; for &amp;quot;constant&amp;quot;.&lt;&#x2F;li&gt;
&lt;li&gt;Encode expression &amp;quot;plus&amp;quot; that denotes adding up two expressions.&lt;&#x2F;li&gt;
&lt;li&gt;Extend &amp;quot;evaluate&amp;quot; to work on it without changing other modules.&lt;&#x2F;li&gt;
&lt;li&gt;Implement &amp;quot;to string&amp;quot; function for both expressions (&amp;quot;plus&amp;quot; and &amp;quot;constant&amp;quot;) without changing other modules.&lt;&#x2F;li&gt;
&lt;li&gt;In the integration module, demonstrate that any function is callable over any defined type case.&lt;&#x2F;li&gt;
&lt;li&gt;Erase all code for &amp;quot;plus&amp;quot; and &amp;quot;to string&amp;quot;.&lt;&#x2F;li&gt;
&lt;li&gt;Reimplement &amp;quot;to string&amp;quot; first.&lt;&#x2F;li&gt;
&lt;li&gt;Reimplement &amp;quot;plus&amp;quot; second, then extending &amp;quot;evaluate&amp;quot; and &amp;quot;to string&amp;quot;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;If generic constraint narrowing would be possible in Generic Go as implemented (it was planned to be possible in the original research), we would have been able to write the following code to solve the expression problem in Go:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#282a36;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;&#x2F;&#x2F; package A at time 0
&lt;&#x2F;span&gt;&lt;span&gt;type ExprConst[T any] struct {
&lt;&#x2F;span&gt;&lt;span&gt;	UnConst T
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&#x2F; Currently impossible because receiver arguments have to have exactly the
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&#x2F; same type signature, including specificity of the type parameters, as their
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&#x2F; struct declarations.
&lt;&#x2F;span&gt;&lt;span&gt;func (e ExprConst[int]) Eval() int {
&lt;&#x2F;span&gt;&lt;span&gt;	return e.UnConst
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&#x2F; end of package A at time 0
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&#x2F; package E at time 0
&lt;&#x2F;span&gt;&lt;span&gt;type Evaler interface {
&lt;&#x2F;span&gt;&lt;span&gt;	Eval() int
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&#x2F; end of package E at time 0
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&#x2F; package P at time 1
&lt;&#x2F;span&gt;&lt;span&gt;type ExprPlus[L, R any] struct {
&lt;&#x2F;span&gt;&lt;span&gt;	Left L
&lt;&#x2F;span&gt;&lt;span&gt;	Right R
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&#x2F; Currently impossible
&lt;&#x2F;span&gt;&lt;span&gt;func (e ExprPlus[Evaler, Evaler]) Eval() int {
&lt;&#x2F;span&gt;&lt;span&gt;	return e.Left.Eval() + e.Right.Eval()
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&#x2F; end of package P at time 1
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&#x2F; package E at time 2
&lt;&#x2F;span&gt;&lt;span&gt;type Evaler ...
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;type Shower interface {
&lt;&#x2F;span&gt;&lt;span&gt;	Show() string
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&#x2F; end of package E at time 2
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&#x2F; package A at time 2
&lt;&#x2F;span&gt;&lt;span&gt;type ExprConst...
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;func ...Eval() int...
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;func (e ExprConst[int]) Show() string {
&lt;&#x2F;span&gt;&lt;span&gt;	return strconv.Itoa(e.Const)
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&#x2F; end of package A at time 2
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&#x2F; package P at time 2
&lt;&#x2F;span&gt;&lt;span&gt;type ExprPlus...
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;func ...Eval() int...
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;func (e ExprPlus[Shower, Shower]) Show() string {
&lt;&#x2F;span&gt;&lt;span&gt;	return fmt.Sprintf(&amp;quot;( %s + %s )&amp;quot;, e.Left.Show(), e.Right.Show())
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&#x2F; end of package P
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&#x2F; package main at time 2
&lt;&#x2F;span&gt;&lt;span&gt;type Expr interface {
&lt;&#x2F;span&gt;&lt;span&gt;	Evaler
&lt;&#x2F;span&gt;&lt;span&gt;	Shower
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;func main() {
&lt;&#x2F;span&gt;&lt;span&gt;	var e Expr = ExprPlus[Expr]{
&lt;&#x2F;span&gt;&lt;span&gt;		ExprPlus[Expr]{
&lt;&#x2F;span&gt;&lt;span&gt;			ExprConst[Expr]{ 30 },
&lt;&#x2F;span&gt;&lt;span&gt;			ExprConst[Expr]{ 11 },
&lt;&#x2F;span&gt;&lt;span&gt;		},
&lt;&#x2F;span&gt;&lt;span&gt;		ExprConst[Expr]{ 1 }
&lt;&#x2F;span&gt;&lt;span&gt;	}
&lt;&#x2F;span&gt;&lt;span&gt;	fmt.Printf(&amp;quot;%d = %s&amp;quot;, e.Eval(), e.Show())
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&#x2F; end of package main
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then, when one would run this, the output would be &lt;code&gt;42 = ( ( 30 + 11 ) + 1 )&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Quoting Robert Griesemer, one of the contributors to the FG paper and one of the main implementers of Generic Go&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Even though we can type-check that, we don&#x27;t know to implement it efficiently in the presence of interfaces (which would also have methods with corresponding type parameters).&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Maybe some day...&lt;&#x2F;p&gt;
&lt;h2 id=&quot;more-evidence-of-usefulness-of-r-d-in-type-systems&quot;&gt;More evidence of usefulness of R&amp;amp;D in type systems&lt;a class=&quot;zola-anchor&quot; href=&quot;#more-evidence-of-usefulness-of-r-d-in-type-systems&quot; aria-label=&quot;Anchor link for: more-evidence-of-usefulness-of-r-d-in-type-systems&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;There are many other examples that demonstrate adoption of programming language theory results in mainstream languages. To name a few:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Rediscovery of higher kinded types in C++ (something very little type systems allow for natively), and a long process of evolution to make them ergonomic.&lt;&#x2F;li&gt;
&lt;li&gt;Design and inclusion of higher kinded types into Scala by Martin Odersky.&lt;&#x2F;li&gt;
&lt;li&gt;Allowing for ergonomic higher order functions in C++ and Java&lt;&#x2F;li&gt;
&lt;li&gt;Function type treatment in mainstream languages, from Golang to Rust.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;There is also an innovation that is on the verge of breaking through into mainstream languages.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;structure-aware-type-systems-and-row-polymorphism&quot;&gt;Structure-aware type systems and row polymorphism&lt;a class=&quot;zola-anchor&quot; href=&quot;#structure-aware-type-systems-and-row-polymorphism&quot; aria-label=&quot;Anchor link for: structure-aware-type-systems-and-row-polymorphism&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;doma.dev&#x2F;blog&#x2F;why-type-systems-matter&#x2F;&quot;&gt;As we discussed&lt;&#x2F;a&gt;, type systems, by definition, limit the expressiveness of languages. And yet, they are well worth it as far as budgets are concerned. Let&#x27;s start this post with exploring a classical expressiveness shortcoming of languages with type systems: the problem of operating on heterogenous data.&lt;&#x2F;p&gt;
&lt;p&gt;Imagine we need to store a hierarchy of countries and cities in the same tree. An untyped approach would be simple: make distinct objects for countries, cities, neighbourhoods and then add &lt;code&gt;children&lt;&#x2F;code&gt; field to each, putting necessary objects on lower levels of the hierarchy:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;Dynamic hierarchy in JavaScript&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-Dynamic hierarchy in JavaScript &quot;&gt;&lt;code class=&quot;language-Dynamic hierarchy in JavaScript&quot; data-lang=&quot;Dynamic hierarchy in JavaScript&quot;&gt;&lt;span&gt;let city1 = {&amp;quot;name&amp;quot;: &amp;quot;Riga&amp;quot;, &amp;quot;longestStreet&amp;quot;: &amp;quot;Brivibas&amp;quot;};
&lt;&#x2F;span&gt;&lt;span&gt;let city2 = {&amp;quot;name&amp;quot;: &amp;quot;Zagreb&amp;quot;, &amp;quot;longestStreet&amp;quot;: &amp;quot;Ilica&amp;quot;};
&lt;&#x2F;span&gt;&lt;span&gt;let country1 = {&amp;quot;name&amp;quot;: &amp;quot;Latvia&amp;quot;, &amp;quot;ownName&amp;quot;: &amp;quot;Latvija&amp;quot;, &amp;quot;capital&amp;quot;: city1};
&lt;&#x2F;span&gt;&lt;span&gt;let country2 = {&amp;quot;name&amp;quot;: &amp;quot;Croatia&amp;quot;, &amp;quot;ownName&amp;quot;: &amp;quot;Hrvatska&amp;quot;, &amp;quot;capital&amp;quot;: city2};
&lt;&#x2F;span&gt;&lt;span&gt;let city11 = {&amp;quot;name&amp;quot;: &amp;quot;Zilupe&amp;quot;, &amp;quot;longestStreet&amp;quot;: &amp;quot;Brivibas&amp;quot;};
&lt;&#x2F;span&gt;&lt;span&gt;let city22 = {&amp;quot;name&amp;quot;: &amp;quot;Split&amp;quot;, &amp;quot;longestStreet&amp;quot;: &amp;quot;Domovinskog Rata&amp;quot;};
&lt;&#x2F;span&gt;&lt;span&gt;let world =
&lt;&#x2F;span&gt;&lt;span&gt;  {&amp;quot;name&amp;quot;: &amp;quot;Earth&amp;quot;,
&lt;&#x2F;span&gt;&lt;span&gt;   &amp;quot;children&amp;quot;:
&lt;&#x2F;span&gt;&lt;span&gt;     [{...country1, &amp;quot;children&amp;quot;: [city1, city11]},
&lt;&#x2F;span&gt;&lt;span&gt;      {...country2, &amp;quot;children&amp;quot;: [city2, city22]}]
&lt;&#x2F;span&gt;&lt;span&gt;  };
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Naively, the same can be achieved by having a tree type, parametrised with a union type that encodes either a City or a Country.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;A union type in Haskell&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-A union type in Haskell &quot;&gt;&lt;code class=&quot;language-A union type in Haskell&quot; data-lang=&quot;A union type in Haskell&quot;&gt;&lt;span&gt;data World = World { name :: Text }
&lt;&#x2F;span&gt;&lt;span&gt;data Country = Country { name :: Text, capital :: City }
&lt;&#x2F;span&gt;&lt;span&gt;data City = City { name :: Text, longestStreet :: Text }
&lt;&#x2F;span&gt;&lt;span&gt;data Value = W (World, [Country]) | C (Country, [City]) | T City
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;However, quite some problems arise when we want to extend encoding to also capture streets, for instance. Our union type shall change along with type definition for City. This topic is far from being trivial to solve in a polymorphic fashion in typed languages. There is &lt;a href=&quot;https:&#x2F;&#x2F;qspace.library.queensu.ca&#x2F;bitstream&#x2F;handle&#x2F;1974&#x2F;672&#x2F;Huang_Freeman_Y_200708_PhD.pdf?sequence=1&amp;amp;isAllowed=y&quot;&gt;modern research&lt;&#x2F;a&gt; that shows that it&#x27;s doable by introducing &amp;quot;pattern structures&amp;quot; into structure-aware type systems.&lt;&#x2F;p&gt;
&lt;p&gt;Relevant to the issue of heterogenity, solving problems such as capability tracking and diverse effect systems, is row polymorphism. It&#x27;s another structure-aware approach to polymorphism, which is said to work on types with rows (records), and allows to define functions that are polymorphic in something except for some rows. In our example, a row-polymorphic function over our structure, could perhaps ask for any type for which &lt;code&gt;name :: Text&lt;&#x2F;code&gt; is defined, along with, perhaps, non-zero other rows. It would then accept anything in our heterogenous structure, since everything is named. If it feels to you like this walks like duck typing and quacks like duck typing then yes, you are right. It is exactly a way to formalise duck typing and introduce it into the type systems. It is a common theme, however, that for PLT to be adopted in the industry, systems need to be engineered that implement the theory. But when you introduce one feature to a system, you trade off ease of introduction of other features (this is why we don&#x27;t have and we will never have a universal language that is good at everything). In case of row polymorphism, the challenge is an &lt;a href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;haskell&#x2F;comments&#x2F;8uhj1f&#x2F;what_is_the_status_on_structural_typing_row_types&#x2F;e1fu2g2&#x2F;?utm_source=reddit&amp;amp;utm_medium=web2x&amp;amp;context=3&quot;&gt;efficient representation of records&lt;&#x2F;a&gt;. Gladly, default implementation of PureScript piggy-backs node.js efficiency. We expect row polymorphism to make its way into functional programming languages from already existing implementations in PureScript and an industrial laboratory language Ermine and eventually be adopted in mainstream languages.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;notable-ommissions&quot;&gt;Notable ommissions&lt;a class=&quot;zola-anchor&quot; href=&quot;#notable-ommissions&quot; aria-label=&quot;Anchor link for: notable-ommissions&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;It is hard to provide full survey of polymorphism and tangent topics in one little blog post. This is why we had to pick our battles.
We have considered, but decided to ommit or mention just briefly, the following subjects (with links to introductory posts about them):&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;typelevel.org&#x2F;blog&#x2F;2016&#x2F;08&#x2F;21&#x2F;hkts-moving-forward.html&quot;&gt;Importance of higher-kinded types&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;okmij.org&#x2F;ftp&#x2F;tagless-final&#x2F;index.html&quot;&gt;Using tagless representations to pass expression problem test&lt;&#x2F;a&gt; (&lt;a href=&quot;https:&#x2F;&#x2F;serokell.io&#x2F;blog&#x2F;introduction-tagless-final&quot;&gt;tagless final for intermediate haskellers&lt;&#x2F;a&gt;).&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;doma.2038.io&#x2F;library&#x2F;Practical_type_inference_for_polymorphic_recursion.pdf&quot;&gt;Using polymorphic recursion for typing heterogenous data&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;parting-words&quot;&gt;Parting words&lt;a class=&quot;zola-anchor&quot; href=&quot;#parting-words&quot; aria-label=&quot;Anchor link for: parting-words&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;In most mainstream languages, existing facilities to boost expressiveness of type system is sufficient in majority of cases without sacrificing guarantees. If you find yourself needing more, sometimes introducing refactoring loops into your feature implementation process can be wise. In well-typed systems, refactoring is cheap and introducing such loops be detrimental to time to market compared to using untyped approaches. That said, for the sake of accepting many potential architectures that would be possible if type systems were more rich, we need to press on as a community and create compilers that take novel research ideas or ideas from other languages in a continuous struggle to unify those into ergonomc systems. Furthermore, along with regaining expressiveness, this work often is capable to &lt;a href=&quot;https:&#x2F;&#x2F;serokell.io&#x2F;blog&#x2F;why-dependent-haskell&quot;&gt;tighten the compile-time guarantees&lt;&#x2F;a&gt;. More about it in the upcoming blog post.&lt;&#x2F;p&gt;
&lt;p&gt;All in all, we think that exploration of repeated success of adoption of parametric polymorphism by mainstream languages does good enough job to motivate businesses to look at the proceedings in the field!&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Why type systems matter</title>
		<published>2021-08-26T16:02:02+00:00</published>
		<updated>2021-08-26T16:02:02+00:00</updated>
		<link href="https://doma.dev/blog/why-type-systems-matter/" type="text/html"/>
		<id>https://doma.dev/blog/why-type-systems-matter/</id>
		<content type="html">&lt;h2 id=&quot;tl-dr&quot;&gt;TL;DR&lt;a class=&quot;zola-anchor&quot; href=&quot;#tl-dr&quot; aria-label=&quot;Anchor link for: tl-dr&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Computer programmers expect their language environments to reject bad programs. It&#x27;s largely done with lightweight formal methods.&lt;&#x2F;li&gt;
&lt;li&gt;Runtime monitoring (the thing that tells you that &lt;code&gt;undefined is not a funciton&lt;&#x2F;code&gt;) is an example of such a formal method.&lt;&#x2F;li&gt;
&lt;li&gt;A type system is also an example of such a formal method.&lt;&#x2F;li&gt;
&lt;li&gt;Type systems target a range of properties deemed as &amp;quot;bad&amp;quot;, for which it is guaranteed that programs having those are rejected.&lt;&#x2F;li&gt;
&lt;li&gt;This may and does result in &amp;quot;good&amp;quot; programs having &amp;quot;bad&amp;quot; properties being rejected. We say that it means that type systems limit expresiveness of a language.&lt;&#x2F;li&gt;
&lt;li&gt;&amp;quot;If it compiles, it works&amp;quot; is a dangerous misconception, but there is a synergy between correctness and passing a type check.&lt;&#x2F;li&gt;
&lt;li&gt;Alternative to using type systems, however, is less feasible for adequately-budgeted developments because it moves error detection to later stages of system&#x27;s lifecycle, resulting in significantly larger costs.&lt;&#x2F;li&gt;
&lt;li&gt;Type systems are also great for rapid prototyping, technical validation and deriving specifications from requirements.&lt;&#x2F;li&gt;
&lt;li&gt;Type systems allow you to test for only truly run-time faults, which are more often than not related to side-effects.&lt;&#x2F;li&gt;
&lt;li&gt;If your organisation can cope with the possible friction that type systems bring, not using type systems is irresponsible.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;a-fistful-of-formal-methods&quot;&gt;A fistful of formal methods&lt;a class=&quot;zola-anchor&quot; href=&quot;#a-fistful-of-formal-methods&quot; aria-label=&quot;Anchor link for: a-fistful-of-formal-methods&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;We want our programming language environments at large to be able to tell well-behaved programs from those that behave poorly. There are several ways to achieve this.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Runtime monitoring, which considers things like operations on incompatible objects (a la Python and JavaScript) and underappreciated contract programming based on preconditions and postconditions, as well as invariant checking (a la &lt;a href=&quot;https:&#x2F;&#x2F;www.eiffel.org&#x2F;doc&#x2F;solutions&#x2F;Design_by_Contract_and_Assertions&quot;&gt;Eiffel&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;dlang.org&#x2F;spec&#x2F;contracts.html&quot;&gt;DLang&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Some will remember model-driven engineering with UML modelling (my Vim highlighted &amp;quot;UML&amp;quot; as a non-existent word! It brings me joy). Automatically deriving constraints from such models and rejecting models that are self-contradicting or breaking some constraints. (a la &lt;a href=&quot;https:&#x2F;&#x2F;ieeexplore.ieee.org&#x2F;document&#x2F;6229788&quot;&gt;EMFtoCSP&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Both digital and &lt;a href=&quot;https:&#x2F;&#x2F;d-nb.info&#x2F;1010333739&#x2F;34&quot;&gt;analog&lt;&#x2F;a&gt; circuits can be accepted or rejected based on automatically derived finite state machine models and checking for desired properties.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Type systems for rejecting classes of poorly-behaved programs statically, during compilation (a la Java, Haskell).&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;A rather interesting observation is that these discriminators should be reproducible, which calls for underlying formalisms. Furthermore, it&#x27;s preferred that domain experts (JavaScript programmers, UML architects, embedded systems engineers) can reap benefits from those. That property is called &amp;quot;lightweight&amp;quot; in culture. When we put these considerations together, we see that all of these things, including JavaScript&#x27;s runtime monitoring, which many people may deem as basic, are lightweight formal methods! Not scary at all.&lt;&#x2F;p&gt;
&lt;p&gt;Not all formal methods, however, are made for the same reason and not everything achievable with one can be achieved with another. To illustrate that, consider the following use-case: we build up an array of validation functions and then, at the validation site we call them one by one.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#282a36;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;01 |    let module1 = {
&lt;&#x2F;span&gt;&lt;span&gt;02 |      defaultValidators: [
&lt;&#x2F;span&gt;&lt;span&gt;03 |        (x) =&amp;gt; 2 == x.split(&amp;#39; &amp;#39;).length,
&lt;&#x2F;span&gt;&lt;span&gt;04 |      ],
&lt;&#x2F;span&gt;&lt;span&gt;05 |      validate: (input) =&amp;gt; (fs) =&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;06 |        fs.reduce((acc, f) =&amp;gt; acc &amp;amp;&amp;amp; f(input), true),
&lt;&#x2F;span&gt;&lt;span&gt;07 |    };
&lt;&#x2F;span&gt;&lt;span&gt;08 |
&lt;&#x2F;span&gt;&lt;span&gt;09 |    let module2 = {
&lt;&#x2F;span&gt;&lt;span&gt;10 |      alsoCapitalised: [
&lt;&#x2F;span&gt;&lt;span&gt;11 |        (x) =&amp;gt;
&lt;&#x2F;span&gt;&lt;span&gt;12 |           x.split(&amp;#39; &amp;#39;).reduce(
&lt;&#x2F;span&gt;&lt;span&gt;13 |             (acc, x) =&amp;gt; acc &amp;amp;&amp;amp; (&#x2F;[A-Z]&#x2F;.test(x[0])), true
&lt;&#x2F;span&gt;&lt;span&gt;14 |           )
&lt;&#x2F;span&gt;&lt;span&gt;15 |      ] + module1.defaultValidators,
&lt;&#x2F;span&gt;&lt;span&gt;16 |    }
&lt;&#x2F;span&gt;&lt;span&gt;17 |
&lt;&#x2F;span&gt;&lt;span&gt;18 |    let main = {
&lt;&#x2F;span&gt;&lt;span&gt;19 |      main: (input) =&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;20 |        let validators = module2.alsoCapitalised;
&lt;&#x2F;span&gt;&lt;span&gt;21 |        if (module1.validate(input)(validators)) {
&lt;&#x2F;span&gt;&lt;span&gt;22 |          console.log(&amp;quot;It&amp;#39;s time to open the door&amp;quot;);
&lt;&#x2F;span&gt;&lt;span&gt;23 |        }
&lt;&#x2F;span&gt;&lt;span&gt;24 |      }
&lt;&#x2F;span&gt;&lt;span&gt;25 |    }
&lt;&#x2F;span&gt;&lt;span&gt;26 |
&lt;&#x2F;span&gt;&lt;span&gt;27 |    main.main(&amp;quot;Viktor Tsoi&amp;quot;);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;When we run this code, the following error will be reported:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#282a36;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;Uncaught TypeError: fs.reduce is not a function
&lt;&#x2F;span&gt;&lt;span&gt;    validate debugger eval code:6
&lt;&#x2F;span&gt;&lt;span&gt;    main debugger eval code:21
&lt;&#x2F;span&gt;&lt;span&gt;    &amp;lt;anonymous&amp;gt; debugger eval code:27
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The true place where the error happens is line 15. Getting there from lines 6 and 21 would probably require a little bit of debugging, especially in a real project. Indeed, the error happens due to nonsense operation &lt;code&gt;+&lt;&#x2F;code&gt; over two arrays. Let&#x27;s fix it:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#282a36;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;15 | ].concat(module1.defaultValidators),
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;When we run the code again, we get the expected message in the log:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#282a36;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;It&amp;#39;s time to open the door
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let&#x27;s compare runtime monitoring with a type system.&lt;&#x2F;p&gt;
&lt;p&gt;Here&#x27;s the code with the same error in Haskell.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;Code snippet showing a similar Haskell compile time error&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-Code snippet showing a similar Haskell compile time error &quot;&gt;&lt;code class=&quot;language-Code snippet showing a similar Haskell compile time error&quot; data-lang=&quot;Code snippet showing a similar Haskell compile time error&quot;&gt;&lt;span&gt;01 | {-# LANGUAGE OverloadedStrings #-}
&lt;&#x2F;span&gt;&lt;span&gt;02 | import qualified Data.Text as T
&lt;&#x2F;span&gt;&lt;span&gt;03 | import Data.Text( Text )
&lt;&#x2F;span&gt;&lt;span&gt;04 | import Data.Char( isUpper )
&lt;&#x2F;span&gt;&lt;span&gt;05 |
&lt;&#x2F;span&gt;&lt;span&gt;06 | defaultValidators :: [Text -&amp;gt; Bool]
&lt;&#x2F;span&gt;&lt;span&gt;07 | defaultValidators = [\x -&amp;gt; 2 == (length $ T.splitOn &amp;quot; &amp;quot; x)]
&lt;&#x2F;span&gt;&lt;span&gt;08 |
&lt;&#x2F;span&gt;&lt;span&gt;09 | validate :: Text -&amp;gt; [Text -&amp;gt; Bool] -&amp;gt; Bool
&lt;&#x2F;span&gt;&lt;span&gt;10 | validate input fs = foldl (\acc f -&amp;gt; acc &amp;amp;&amp;amp; f input) True fs
&lt;&#x2F;span&gt;&lt;span&gt;11 |
&lt;&#x2F;span&gt;&lt;span&gt;12 | alsoCapitalised :: [Text -&amp;gt; Bool]
&lt;&#x2F;span&gt;&lt;span&gt;13 | alsoCapitalised = [\x -&amp;gt; foldl (\acc w -&amp;gt; acc &amp;amp;&amp;amp; (isUpper $ T.head w))
&lt;&#x2F;span&gt;&lt;span&gt;14 |                                True
&lt;&#x2F;span&gt;&lt;span&gt;15 |                                (T.splitOn &amp;quot; &amp;quot; x)] + defaultValidators
&lt;&#x2F;span&gt;&lt;span&gt;16 |
&lt;&#x2F;span&gt;&lt;span&gt;17 | main :: IO ()
&lt;&#x2F;span&gt;&lt;span&gt;18 | main =
&lt;&#x2F;span&gt;&lt;span&gt;19 |   case validate input defaultValidators of
&lt;&#x2F;span&gt;&lt;span&gt;20 |     True -&amp;gt; putStrLn &amp;quot;It&amp;#39;s time to open the door&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;21 |     _    -&amp;gt; putStrLn &amp;quot;Close the door behind me&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;22 |   where
&lt;&#x2F;span&gt;&lt;span&gt;23 |     input = &amp;quot;Viktor Tsoi&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;When we try to compile it, we&#x27;re going to get an error that says exactly what is wrong. To be able to apply &lt;code&gt;+&lt;&#x2F;code&gt;, operands had to be classified as numbers via typeclass &lt;code&gt;Num&lt;&#x2F;code&gt;. This typeclass doesn&#x27;t include lists of validator functions. Note that if we would want to define addition on such values, we would be able to, by providing an appropriate instance of &lt;code&gt;Num&lt;&#x2F;code&gt;. But it&#x27;s a rather horrible idea, so we&#x27;ll fix the bug instead.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;pinpointing the faulty location&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-pinpointing the faulty location &quot;&gt;&lt;code class=&quot;language-pinpointing the faulty location&quot; data-lang=&quot;pinpointing the faulty location&quot;&gt;&lt;span&gt;&#x2F;tmp&#x2F;hi.hs:13:19: error:
&lt;&#x2F;span&gt;&lt;span&gt;    No instance for (Num [Text -&amp;gt; Bool]) arising from a use of &amp;#39;+&amp;#39;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;With this error, we quickly can replace line 15 with one using &lt;code&gt;++&lt;&#x2F;code&gt;, the list concatenation operator:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;Fixed line 15&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-Fixed line 15 &quot;&gt;&lt;code class=&quot;language-Fixed line 15&quot; data-lang=&quot;Fixed line 15&quot;&gt;&lt;span&gt;15 |                                (T.splitOn &amp;quot; &amp;quot; x)] ++ defaultValidators
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;When we run this one, we get the correct result!&lt;&#x2F;p&gt;
&lt;p&gt;Static checking allows us to catch many classes of errors like this one early, which saves a lot of money, since—as systems engineering teaches us—the cost of fixing a fault in a system grows exponentially as a function of how far it is from the requirement gathering stage in the lifecycle of a system.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;benefits-of-using-type-systems&quot;&gt;Benefits of using type systems&lt;a class=&quot;zola-anchor&quot; href=&quot;#benefits-of-using-type-systems&quot; aria-label=&quot;Anchor link for: benefits-of-using-type-systems&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Type systems come in different shapes and sizes: different type systems may be geared to eliminate different classes of incorrect programs. However, most type systems—collaterally—eliminate programmers&#x27; errors such as incomplete case analyses, mismatched units, et cetera. For example, if we get rid of line 21 in the Haskell listing entirely, in a well-configured GHC (which treats warnings as errors and warns about everything &amp;quot;suspicious&amp;quot;), we&#x27;ll get the following error, indicating incomplete case analysis:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;Haskell error&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-Haskell error &quot;&gt;&lt;code class=&quot;language-Haskell error&quot; data-lang=&quot;Haskell error&quot;&gt;&lt;span&gt;&#x2F;tmp&#x2F;hi.hs:19:3: error: [-Wincomplete-patterns, -Werror=incomplete-patterns]
&lt;&#x2F;span&gt;&lt;span&gt;    Pattern match(es) are non-exhaustive
&lt;&#x2F;span&gt;&lt;span&gt;    In a case alternative: Patterns not matched: False
&lt;&#x2F;span&gt;&lt;span&gt;   |
&lt;&#x2F;span&gt;&lt;span&gt;19 |   case validate input defaultValidators of
&lt;&#x2F;span&gt;&lt;span&gt;   |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Of course, it&#x27;s impossible to reap this benefit without a certain wit and discipline. I like to call that discipline &amp;quot;tight typing&amp;quot;, many Haskellers call it &amp;quot;having as concrete data structures as possible&amp;quot; (it&#x27;s an elaboration of the mantra &amp;quot;abstract functions, concrete data&amp;quot;). For instance, the &lt;code&gt;DummyTag&lt;&#x2F;code&gt; type you have seen earlier is loose, because it is used in the places of the model accepting types with incompatible terms. Quoting my colleague:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Nothing prevents you to subtract height from pressure if both of those are encoded as Float.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Type checkers are powerful refactoring tools. Anecdotally, at work, once we had to restructure approximately fifty modules while separating part of those into a library and fusing arguments into structures in another part of those. The whole refactoring was done and released by one person in one working day. It would have been impossible without a type checker to ensure the completeness of said refactoring. Another anecdote comes from my colleague:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;When I worked for AlphaSheets.com (a startup &amp;quot;acquihired&amp;quot; by Google), I refactored the whole codebase, threading through an App monad instead of IO. I did this for a week in part due to painful and regular rebasing onto the main branch. But when the thing was compiled, the only tests that failed were the ones covering a place that was stubbed with undefined.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Notorious for a steep learning curve and perceived feature development slow-down, languages with type systems—granted a certain engineering savviness—can serve as amazing facilitators of rapid prototyping. The goal of prototyping is often to figure out the best specification for the requirements at hand. Expressive type systems often allow encoding relationships between domain entities without writing complex business logic. If one views types as claims that something is possible and values of said types as proofs that it indeed is possible, this approach makes a lot of sense. Of course, mileage can vary and it works better the fewer side-effects there are in a system, but remember that you can simulate side effects via type encodings too! For instance, instead of figuring out a proper way to do cryptography while prototyping, we can encode an interface of a crypto-system and populate it with dummy functions, complying with it:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#282a36;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;data PKC pass sk pk slip sig sigmsg enc plain cipher = PKC
&lt;&#x2F;span&gt;&lt;span&gt;  { -- | Initial key derivation function
&lt;&#x2F;span&gt;&lt;span&gt;    kdf :: pass -&amp;gt; (sk, pk, slip),
&lt;&#x2F;span&gt;&lt;span&gt;    -- | Rederive with kdf
&lt;&#x2F;span&gt;&lt;span&gt;    rekdf :: slip -&amp;gt; pass -&amp;gt; (sk, pk),
&lt;&#x2F;span&gt;&lt;span&gt;    -- | Sign data with key @sk@ and produce a detached @signature@
&lt;&#x2F;span&gt;&lt;span&gt;    -- possibly containing @pk@ for verification.
&lt;&#x2F;span&gt;&lt;span&gt;    sign :: sigmsg -&amp;gt; (sk, pk) -&amp;gt; signature pk,
&lt;&#x2F;span&gt;&lt;span&gt;    -- | Verifies @signature@ container&amp;#39;s validity.
&lt;&#x2F;span&gt;&lt;span&gt;    verify :: sigmsg -&amp;gt; signature pk -&amp;gt; Bool,
&lt;&#x2F;span&gt;&lt;span&gt;    -- | Encrypt data of type @plain@ to the key @pk@ and produce @encrypted@
&lt;&#x2F;span&gt;&lt;span&gt;    -- containing @cipher@.
&lt;&#x2F;span&gt;&lt;span&gt;    encrypt :: plain -&amp;gt; pk -&amp;gt; encrypted pk cipher,
&lt;&#x2F;span&gt;&lt;span&gt;    -- | Decrypts @cipher@, contained in an @encrypted@ container into @plain@.
&lt;&#x2F;span&gt;&lt;span&gt;    decrypt :: encrypted pk cipher -&amp;gt; sk -&amp;gt; Maybe plain
&lt;&#x2F;span&gt;&lt;span&gt;  }
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is a model of public key cryptography. Populating this model with functions would, together with tests that verify correct behaviours and error handling of a cryptosystem, serve as proof of the possibility of a correct implementation of public key cryptography in Haskell. Perhaps more importantly, it would also provide an interactive specification for doing so, perhaps even in another language! Let&#x27;s give an example of some functions slotting into that model.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#282a36;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;data DummyTag = DummySK | DummyPK | DummySlip
&lt;&#x2F;span&gt;&lt;span&gt;  deriving (Show, Eq)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;-- | Note that we abuse the fact that in dummy implementation
&lt;&#x2F;span&gt;&lt;span&gt;-- secret key and public key are both represented with a
&lt;&#x2F;span&gt;&lt;span&gt;-- DummyTagged type alias to embed secret key together with
&lt;&#x2F;span&gt;&lt;span&gt;-- the message.
&lt;&#x2F;span&gt;&lt;span&gt;newtype DummySigned msg key = DummySigned {sig :: (key, (key, msg))}
&lt;&#x2F;span&gt;&lt;span&gt;  deriving (Show, Eq)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;-- ...
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;type DummyTagged = (DummyTag, ByteString)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;-- ...
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;dummyKdf :: ByteString -&amp;gt; IO (Maybe (DummyTagged, DummyTagged, DummyTagged))
&lt;&#x2F;span&gt;&lt;span&gt;dummyKdf pass = pure $ Just ((DummyPK, pass), (DummySK, pass), (DummySlip, pass))
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;dummyRekdf :: DummyTagged -&amp;gt; ByteString -&amp;gt; Maybe (DummyTagged, DummyTagged)
&lt;&#x2F;span&gt;&lt;span&gt;dummyRekdf (DummySlip, x) pass =
&lt;&#x2F;span&gt;&lt;span&gt;  go (x == pass)
&lt;&#x2F;span&gt;&lt;span&gt;  where
&lt;&#x2F;span&gt;&lt;span&gt;    go True = Just ((DummyPK, pass), (DummySK, pass))
&lt;&#x2F;span&gt;&lt;span&gt;    go False = Nothing
&lt;&#x2F;span&gt;&lt;span&gt;dummyRekdf _ _ = error &amp;quot;DummySlip expected in the 1st argument&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;-- ...
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;dummySign :: (DummyTagged, DummyTagged) -&amp;gt; msg -&amp;gt; DummySigned msg DummyTagged
&lt;&#x2F;span&gt;&lt;span&gt;dummySign (verificationKey@(DummyPK, _), signingKey@(DummySK, _)) blob =
&lt;&#x2F;span&gt;&lt;span&gt;  DummySigned (verificationKey, (signingKey, blob))
&lt;&#x2F;span&gt;&lt;span&gt;dummySign _ _ = error &amp;quot;The first argument has to be a tuple of DummySK and DummyPK&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;-- | Note that we&amp;#39;re not comparing public key with secret key
&lt;&#x2F;span&gt;&lt;span&gt;-- but rather compare embedded bytestrings which match if the keys
&lt;&#x2F;span&gt;&lt;span&gt;-- were derived from the same password by kdf
&lt;&#x2F;span&gt;&lt;span&gt;dummyVerify :: Eq a =&amp;gt; DummySigned a DummyTagged -&amp;gt; a -&amp;gt; Bool
&lt;&#x2F;span&gt;&lt;span&gt;dummyVerify (DummySigned ((DummyPK, signedAs), ((DummySK, signedWith), signedWhat))) candidate =
&lt;&#x2F;span&gt;&lt;span&gt;  (signedAs == signedWith) &amp;amp;&amp;amp; (candidate == signedWhat)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now to keep prototyping, we just need to instantiate PKC data type with this collection of functions. Later on, when we switch to a real cryptographic system, we will use it to make another value of type PKC. If all the properties of the initial prototype were preserved, it shall serve as proof to the claim that &amp;quot;production public key cryptographic systems exist as modelled&amp;quot;. We can and should verify that early, but not too early to slow the prototyping down. Similarly, HTTP client-server interactions can be modelled. After the prototype is completed, one will end up with a runnable, compilable specification for the software they&#x27;re about to write. What&#x27;s fairly amazing is that if the company doesn&#x27;t want to switch from Haskell (or whichever strongly-typed language they were using to model) to another language for the actual product, they can repurpose this prototype for an incremental rewrite into an MVP!&lt;&#x2F;p&gt;
&lt;p&gt;Now to the last, but not the least important benefit of type systems! These days, usage of higher-order and anonymous functions is prominent even in more conservative ecosystems like Java&#x27;s. Type systems greatly assist in reasoning about the code&#x27;s overall behaviour. In general, type systems are one of many tools for writing self-documenting code. An illustration for those, who (like me) keep forgetting the order of the accumulator and an the iterated value in reducers:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#282a36;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;Prelude&amp;gt; :t foldl
&lt;&#x2F;span&gt;&lt;span&gt;foldl :: Foldable t =&amp;gt; (b -&amp;gt; a -&amp;gt; b) -&amp;gt; b -&amp;gt; t a -&amp;gt; b
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Yeah, if the language&#x27;s ecosystem is tightly integrated with the underlying type system, amazing things are possible, from simple type signature lookups at your fingertips to full-blown type signature search engines like &lt;a href=&quot;https:&#x2F;&#x2F;hoogle.haskell.org&#x2F;&quot;&gt;Hoogle&lt;&#x2F;a&gt; and Serokell&#x27;s &lt;a href=&quot;https:&#x2F;&#x2F;hackage-search.serokell.io&#x2F;&quot;&gt;hackage-search&lt;&#x2F;a&gt;. Conversely, if the language ecosystem evolved independently from type system, such as TypeScript and Dialyzer extending their respective languages with success typings, likely, self-documenting benefits and improved discoverability will be way less pronounced, if at all.&lt;&#x2F;p&gt;
&lt;p&gt;Type systems also enable and encourage writing composable code, meaning that the programmers are nudged towards writing well-structured and modular codebases, no matter what is the unit of modularity: a Java class or a Haskell module. Of course, there are ways to write spaghetti code in any language, but it&#x27;s harder when the whole ecosystem imposes structure.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;drawbacks-of-type-systems&quot;&gt;Drawbacks of type systems&lt;a class=&quot;zola-anchor&quot; href=&quot;#drawbacks-of-type-systems&quot; aria-label=&quot;Anchor link for: drawbacks-of-type-systems&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Type systems aren&#x27;t entirely free. Both the users (programmers) and the computer itself have to do extra work to write a program that would be accepted by a language with a type system. Sometimes, that work takes non-trivial amounts of computational time, but in practice, it&#x27;s seldom more computationally intense than, say, code generation via templates.&lt;&#x2F;p&gt;
&lt;p&gt;Also, not quite a drawback, but rather something many people don&#x27;t understand about type systems. There&#x27;s an &amp;quot;if it compiles, it works&amp;quot; meme, but it&#x27;s extremely misleading. Type systems, by their static nature, can&#x27;t prove the presence of features of a program, only absence. But this yields a couple of actual drawbacks:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;With type systems, you almost always pick your fights. Languages geared towards eliminating one kind of bad program behaviours won&#x27;t eliminate another, perhaps, side-stepping it altogether by deferring it to the language runtime.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Scrutiny, thus power, of type systems is always in tension with expressiveness, which is understood as the measure of the programs that are well-behaved at runtime, which are rejected by the type checker.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Sometimes complex type checking algorithms rely on heuristics, which limit expressiveness in ways, &lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=jNbb5JVuq-o&quot;&gt;unexpected by the user&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;bottom-line&quot;&gt;Bottom line&lt;a class=&quot;zola-anchor&quot; href=&quot;#bottom-line&quot; aria-label=&quot;Anchor link for: bottom-line&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;We&#x27;ll end this article with a nice heuristic for architects to think about using type systems. Perform the following thought experiment:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Approximate how much would it cost to write, deploy and run a 100%-coverage random testing system, searching for runtime errors (in our JS example, it would be a test making sure that there is no validator crashed by a string and there is no call in the program that crashes it).&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Approximate how much would it cost to train developers to use a &amp;quot;tight&amp;quot; type system, which would give the same sort of guarantees &amp;quot;for free&amp;quot; and in static fashion (many different kinds of tests are still needed in this approach, but the tests we&#x27;ve described in p.1 are given to us for free by the type checker).&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;If cost 2 is even comparable to, let alone lower than, cost 1, going for using type systems to refuse incorrect programs is warranted. Quoting &amp;quot;The Toyota Way&amp;quot;:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Focusing on quality actually reduced cost more than focusing only on cost.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Getting things done with shell scripting</title>
		<published>2021-04-09T14:25:00+00:00</published>
		<updated>2021-04-09T14:25:00+00:00</updated>
		<link href="https://doma.dev/blog/get-things-done-with-bash/" type="text/html"/>
		<id>https://doma.dev/blog/get-things-done-with-bash/</id>
		<content type="html">&lt;h2 id=&quot;tl-dr&quot;&gt;TL;DR&lt;a class=&quot;zola-anchor&quot; href=&quot;#tl-dr&quot; aria-label=&quot;Anchor link for: tl-dr&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;When to resort to shell scripts
&lt;ul&gt;
&lt;li&gt;Portability is important&lt;&#x2F;li&gt;
&lt;li&gt;Problem at hand is compact&lt;&#x2F;li&gt;
&lt;li&gt;File system interaction&lt;&#x2F;li&gt;
&lt;li&gt;Command-line program automation&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;When to search for an alternative
&lt;ul&gt;
&lt;li&gt;Extensibility is required&lt;&#x2F;li&gt;
&lt;li&gt;Coding mission-critical stuff&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Shell scripting is dangerous, use shellcheck and limit yourself in idioms used&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Computer consoles are the second most important UX improvement in computing, surpassed only by window managers.
Consoles went a long way from allowing the computer user to enter programs to be executed by a single-process operating system to converting them into toolboxes.
Gladly, most of it was happening in Bell Labs under the supervision of the unstoppable innovator &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Douglas_McIlroy&quot;&gt;Douglas McIlroy&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;a href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20201004064728&#x2F;https:&#x2F;&#x2F;www.multicians.org&#x2F;mgs.html&quot;&gt;Multics &amp;quot;shell&amp;quot;&lt;&#x2F;a&gt;, just like inputs on other terminal-enabled computers of that era, was an instrument to accept a program and execute it on the Multics OS, the predecessor of UNIX.
The earliest versions of the Multics shell already had input&#x2F;output redirection. It wasn&#x27;t until Douglas McIlroy &lt;a href=&quot;https:&#x2F;&#x2F;corecursive.com&#x2F;021-gods-programming-language-with-philip-wadler&#x2F;&quot;&gt;discovered (not invented)&lt;&#x2F;a&gt; command pipelines, it became a golden standard across all the operating systems.&lt;&#x2F;p&gt;
&lt;p&gt;Pipelining and UNIX philosophy is allowing for writing small problem-specific programs that can be later composed.
But the biggest reason for the usage of UNIX shell scripts in 2021 is portability.
Indeed, every modern system has a UNIX shell readily available.
Furthermore, often making a reasonably well-written shell script is &amp;quot;good enough for the job&amp;quot;.
But how does one do that?
Let&#x27;s explore the answer to this question, assuming that the reader already knows the &lt;a href=&quot;https:&#x2F;&#x2F;livecodestream.dev&#x2F;post&#x2F;introduction-to-bash-for-beginners&#x2F;&quot;&gt;very basics of shell scripting&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;minimal-shell-scripts-in-bash&quot;&gt;Minimal shell scripts in bash&lt;a class=&quot;zola-anchor&quot; href=&quot;#minimal-shell-scripts-in-bash&quot; aria-label=&quot;Anchor link for: minimal-shell-scripts-in-bash&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;ctf.cdn.doma.dev&#x2F;thou-shall-not-establish-bumblebee.jpg&quot; alt=&quot;An Reannissance meme with an evil-looking man saying &amp;quot;thou shalt not establish bumblebee&amp;quot;&quot; &#x2F;&gt;
Let&#x27;s get the most important consideration out of the way.
Writing secure and reliable shell scripts is &lt;a href=&quot;https:&#x2F;&#x2F;www.netmeister.org&#x2F;blog&#x2F;MrMEEE&#x2F;backup.html&quot;&gt;almost impossible&lt;&#x2F;a&gt;.
The least one can do is to use &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;koalaman&#x2F;shellcheck&quot;&gt;&lt;code&gt;shellcheck&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, which has &lt;a href=&quot;https:&#x2F;&#x2F;marketplace.visualstudio.com&#x2F;items?itemName=timonwong.shellcheck&quot;&gt;integration with VSCode&lt;&#x2F;a&gt;.
Furthermore, be very disciplined with user inputs and do your best to quote every argument that has a variable in it.&lt;&#x2F;p&gt;
&lt;p&gt;Alright, with that out of the way, let&#x27;s talk about step-by-step items one has to do to make a reasonable shell script.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;setting-up-your-shell-environment&quot;&gt;Setting up your shell environment&lt;a class=&quot;zola-anchor&quot; href=&quot;#setting-up-your-shell-environment&quot; aria-label=&quot;Anchor link for: setting-up-your-shell-environment&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Before starting programming shells, we need to first determine which shell scripting language will we use.
There are three schools of thought about this:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Use &lt;code&gt;bash&lt;&#x2F;code&gt; by default. Bash is a reasonable middle ground between having a lot of features and being portable since it is shipped with each of the popular OS.&lt;&#x2F;li&gt;
&lt;li&gt;Use &lt;code&gt;sh&lt;&#x2F;code&gt; by default and &lt;code&gt;bash&lt;&#x2F;code&gt; when advanced features are needed. This is a purist approach.
It offers the most portability but requires distinguishing between basic features and bash-exclusive features.&lt;&#x2F;li&gt;
&lt;li&gt;Use &lt;code&gt;zsh&lt;&#x2F;code&gt;, &lt;code&gt;fish&lt;&#x2F;code&gt; or some other &amp;quot;hipster&amp;quot; shell for everything. I&#x27;m mentioning this school of thought for completeness. Since it breaks portability, people who pick this option may just as well code in Python.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;As one can guess, we suggest simply using &lt;code&gt;bash&lt;&#x2F;code&gt; for everything.
Of course, Apple seems to be deprecating &lt;code&gt;bash&lt;&#x2F;code&gt; as the default shell, but it&#x27;s not going anywhere from mac os systems.
Conversely, Windows 10 has support for reasonable &lt;code&gt;bash&lt;&#x2F;code&gt; integration with its WSL programme.
It requires some setup, but these days WSL2 seems to become the default for Windows development.&lt;&#x2F;p&gt;
&lt;p&gt;Besides, &lt;code&gt;bash&lt;&#x2F;code&gt; scripts have fine-grained built-in support for lowering the impact of the inevitable bugs.
While setting up your shell, we suggest you use the following &lt;a href=&quot;https:&#x2F;&#x2F;www.gnu.org&#x2F;software&#x2F;bash&#x2F;manual&#x2F;bash.html#The-Set-Builtin&quot;&gt;options&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;#!&#x2F;usr&#x2F;bin&#x2F;env bash
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;set&lt;&#x2F;span&gt;&lt;span&gt; -euo pipefail
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Optionally add &lt;code&gt;-x&lt;&#x2F;code&gt; for easier debugging.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;command-line-argument-processing&quot;&gt;Command line argument processing&lt;a class=&quot;zola-anchor&quot; href=&quot;#command-line-argument-processing&quot; aria-label=&quot;Anchor link for: command-line-argument-processing&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;If you, for some reason, want to use shell to write something huge like &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;manpages&#x2F;issues-legacy&quot;&gt;a full-blown issue tracker with git backend&lt;&#x2F;a&gt;, you&#x27;ll need to use &lt;a href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;402377&#x2F;using-getopts-to-process-long-and-short-command-line-options&#x2F;7948533#7948533&quot;&gt;&lt;code&gt;getopts&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; or &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;manpages&#x2F;issues-legacy&#x2F;blob&#x2F;master&#x2F;issues#L30&quot;&gt;make your own despatch system&lt;&#x2F;a&gt;.
In this post, however, we shall consider simple argument processing.
We heavily advocate for short and concise scripts that do one thing and one thing only, after all.&lt;&#x2F;p&gt;
&lt;p&gt;First things first, let&#x27;s see how to print help:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;[[ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;== &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;--help&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;|| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;== &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;-h&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;]]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;; then
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#50fa7b;&quot;&gt;cat &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;&amp;lt;&amp;lt;EOH
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;frgtmv: for each file read from STDIN, forget its filename entirely or amend part of it.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;...
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;#39;&amp;#39;frgtmv&amp;#39;&amp;#39; will then &amp;#39;&amp;#39;mv&amp;#39;&amp;#39; each of these files to &amp;#39;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;\$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;(date +&amp;#39;%Y%m%d%H%M%S%N&amp;#39;)&amp;#39;&amp;#39;, preserving the file extension.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;...
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;EOH
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;exit
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;fi
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Key points:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;We&#x27;re using &lt;code&gt;&amp;lt;&amp;lt;EOH &#x2F; EOH&lt;&#x2F;code&gt; &amp;quot;heredoc&amp;quot; syntax and make sure that we don&#x27;t indent the lines under it.&lt;&#x2F;li&gt;
&lt;li&gt;We&#x27;re escaping special characters like &lt;code&gt;$&lt;&#x2F;code&gt; with a backslash. If we wouldn&#x27;t, bash would evaluate internals in a subshell.&lt;&#x2F;li&gt;
&lt;li&gt;Don&#x27;t forget to &lt;code&gt;exit&lt;&#x2F;code&gt; after printing the help!&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Now let&#x27;s use &lt;code&gt;-n&lt;&#x2F;code&gt;, a predicate checking if a variable is set, to prepare the variables needed.
Often we want to set up defaults at the beginning of the file:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;_mode&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;forget&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;_pattern_from&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;_replace_with&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;[ &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ffb86c;&quot;&gt;-n &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;; then
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;_mode&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;amend&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;_pattern_from&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;fi
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;[ &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ffb86c;&quot;&gt;-n &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;; then
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;_replace_with&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;fi
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Sometimes you would need to exit if an argument is not supplied.
We use &lt;code&gt;-z&lt;&#x2F;code&gt; that checks if a string is not empty for this:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;# Exit if file or directory is not submitted or not a valid file or directory
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;[ &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ffb86c;&quot;&gt;-z &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;; then
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;echo &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;We really need the first argument&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;exit&lt;&#x2F;span&gt;&lt;span&gt; 228
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;fi
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;stdin-pipes-and-gnu-parallel&quot;&gt;STDIN, pipes and GNU parallel&lt;a class=&quot;zola-anchor&quot; href=&quot;#stdin-pipes-and-gnu-parallel&quot; aria-label=&quot;Anchor link for: stdin-pipes-and-gnu-parallel&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Sometimes you need to receive input from STDIN through a pipe or user input.
It&#x27;s done using &lt;code&gt;read -r&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;while &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;read &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ffb86c;&quot;&gt;-r&lt;&#x2F;span&gt;&lt;span&gt; _x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;; do
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#50fa7b;&quot;&gt;mv&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ffb86c;&quot;&gt; -v &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;_x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot; &amp;quot;$(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#50fa7b;&quot;&gt;date&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt; +&amp;#39;%Y%m%d%H%M%S%N&amp;#39;).${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;_x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;#*&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;.}&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;done
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If you care about performance more than about portability, use &lt;code&gt;cat -&lt;&#x2F;code&gt; to pass your STDIN to GNU parallel, following this pattern:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;function &lt;&#x2F;span&gt;&lt;span style=&quot;color:#50fa7b;&quot;&gt;forget&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#50fa7b;&quot;&gt;mv&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ffb86c;&quot;&gt; -v &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot; &amp;quot;$(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#50fa7b;&quot;&gt;date&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt; +&amp;#39;%Y%m%d%H%M%S%N&amp;#39;).$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;.${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;#*&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;.}&amp;quot;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;export &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ffb86c;&quot;&gt;-f &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;forget &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;# (A)
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;[[ &lt;&#x2F;span&gt;&lt;span&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;_mode &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;== &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;forget&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;]]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;; then
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#50fa7b;&quot;&gt;cat&lt;&#x2F;span&gt;&lt;span&gt; - &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#50fa7b;&quot;&gt;parallel&lt;&#x2F;span&gt;&lt;span&gt; forget {%} {} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;# (B)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;fi
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In &lt;code&gt;(A)&lt;&#x2F;code&gt;, the parallel payload is implemented as a bash function.
Notice the &lt;code&gt;export&lt;&#x2F;code&gt; statement!
We suggest writing payloads that receive two variables: the parallel job ID (&lt;code&gt;{%}&lt;&#x2F;code&gt;) and the currently read out item from the STDIN stream (&lt;code&gt;{}&lt;&#x2F;code&gt;).
The payload is called from &lt;code&gt;(B)&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Here are some interesting &lt;code&gt;parallel&lt;&#x2F;code&gt; techniques:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--keep-order&lt;&#x2F;code&gt; to guarantee that the order of the input will be kept. Requires several file handles per input, which may turn out to be a bottle-neck.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;find . -print0 | parallel -0 f {}&lt;&#x2F;code&gt; to work in null-terminated mode.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;parallel &#x27;echo &amp;quot;{%}:{1}:{2}&amp;quot;;&#x27; ::: 1 2 ::: a b c&lt;&#x2F;code&gt; will prarallelise a Cartesian product of input sets {1,2} × {a,b,c}.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;bash-parameter-expansion&quot;&gt;Bash parameter expansion&lt;a class=&quot;zola-anchor&quot; href=&quot;#bash-parameter-expansion&quot; aria-label=&quot;Anchor link for: bash-parameter-expansion&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Confusing many, if not all new shell users, &amp;quot;&lt;a href=&quot;https:&#x2F;&#x2F;www.gnu.org&#x2F;software&#x2F;bash&#x2F;manual&#x2F;html_node&#x2F;Shell-Parameter-Expansion.html&quot;&gt;parameter expansion&lt;&#x2F;a&gt;&amp;quot; has a veil of mystery around it.
In our humble opinion, there are several causes for this effect:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Parameter expansion is a blanket name that unites accessing values and substituting values.&lt;&#x2F;li&gt;
&lt;li&gt;Within these use-cases, there is a myriad of conditional behaviours and they are decided based on the kind of parameter.&lt;&#x2F;li&gt;
&lt;li&gt;There isn&#x27;t much expansion going on. Word &amp;quot;expanded&amp;quot; is simply an arcane way to say &amp;quot;reduced to a value&amp;quot;.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Let&#x27;s start from the beginning.
A parameter in bash is either a variable (like &lt;code&gt;$HOME&lt;&#x2F;code&gt;), a positional &amp;quot;argument&amp;quot; parameter (like &lt;code&gt;$1&lt;&#x2F;code&gt;), or a special parameter (like &lt;code&gt;$@&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;&amp;quot;Expansion&amp;quot; is the process of &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Reduction_strategy_(lambda_calculus)&quot;&gt;reduction&lt;&#x2F;a&gt; of parameters to values.
Variables expand in the way one would expect from variables.
&lt;a href=&quot;https:&#x2F;&#x2F;www.gnu.org&#x2F;software&#x2F;bash&#x2F;manual&#x2F;html_node&#x2F;Special-Parameters.html&quot;&gt;Special parameters&lt;&#x2F;a&gt;, however, can have context-dependent expansions.
Expansions have special syntaxes to tack on additional computations like string substitution, length calculation, etc.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s use the following variable as an example: &lt;code&gt;x=&amp;quot;a.b.c&amp;quot;&lt;&#x2F;code&gt;.
Here is a list of the most often used parameter expansions, according to us:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Stripping. Use-case: get a file extension or remove a file extension.
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;${x%.*} ≡ a.b&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;${x%%.*} ≡ a&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;${x#*.} ≡ b.c&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;${x##*.} ≡ c&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;String replacement.
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;${x&#x2F;.&#x2F;\!} ≡ a!b.c&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;${x&#x2F;&#x2F;.&#x2F;\!} ≡ a!b!c&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Array enumeration with &lt;code&gt;IFS&lt;&#x2F;code&gt; and &lt;code&gt;[@]&lt;&#x2F;code&gt;.
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;IFS=&amp;quot;.&amp;quot;; for v in ${x[@]}; do echo -n &amp;quot;($v)&amp;quot;; done ≡  (a)(b)(c)&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;You can also construct arrays with a &amp;quot;compound assignment&amp;quot;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;(a b c)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; v &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;x[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bd93f9;&quot;&gt;@&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;; do
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;echo &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ffb86c;&quot;&gt;-n &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;($&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;v&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;)&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;done
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;IFS manipulation is not normally needed.
If you&#x27;re changing the splitting context, you should see if there is another way.
You might be falling victim to the &lt;a href=&quot;https:&#x2F;&#x2F;mywiki.wooledge.org&#x2F;XyProblem&quot;&gt;XY problem&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;This tutorial should provide good-enough techniques to quickly and effectively implement shell scripts that do what you want them to.
Quote your variables, fail fast, make backups to recover from destructive changes, don&#x27;t use too many &amp;quot;advanced features&amp;quot; since they are error-prone, and good luck!&lt;&#x2F;p&gt;
&lt;p&gt;We leave you with some shell scripts we wrote that push the boundaries of what shell should be used to:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;manpages&#x2F;usr-local-bin&#x2F;blob&#x2F;master&#x2F;chess&quot;&gt;A chess clock made in bash&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;git.sr.ht&#x2F;%7Ejonn&#x2F;shmux&#x2F;tree&#x2F;master&#x2F;item&#x2F;shmux&quot;&gt;A script I use daily: spawn or reattach to given project&#x27;s &lt;code&gt;tmux&lt;&#x2F;code&gt; session&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;manpages&#x2F;issues-legacy&#x2F;blob&#x2F;master&#x2F;issues#L5-L15&quot;&gt;Auto-detect canonical path to the script and eval modules residing in &lt;code&gt;include&#x2F;&lt;&#x2F;code&gt; directory&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;manpages&#x2F;issues-legacy&#x2F;blob&#x2F;master&#x2F;include&#x2F;bye.sh&quot;&gt;Terminate&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;manpages&#x2F;issues-legacy&#x2F;blob&#x2F;master&#x2F;issues#L3&quot;&gt;process tree&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;manpages&#x2F;issues-legacy&#x2F;blob&#x2F;master&#x2F;include&#x2F;debug.sh&quot;&gt;printing debug output&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;If there will be community interest, we will take some time to cover extensible shell scripting in Haskell with Turtle.
As usual, reach out to us on &lt;a href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;doma_dev&quot;&gt;Twitter&lt;&#x2F;a&gt; or in the comments on &lt;a href=&quot;https:&#x2F;&#x2F;dev.to&#x2F;doma&quot;&gt;Dev.to&lt;&#x2F;a&gt; or &lt;a href=&quot;https:&#x2F;&#x2F;doma-dev.medium.com&#x2F;&quot;&gt;Medium&lt;&#x2F;a&gt; mirrors.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Parser combinators in Rust</title>
		<published>2021-03-30T17:20:00+00:00</published>
		<updated>2021-03-30T17:20:00+00:00</updated>
		<link href="https://doma.dev/blog/parsing-stuff-in-rust/" type="text/html"/>
		<id>https://doma.dev/blog/parsing-stuff-in-rust/</id>
		<content type="html">&lt;h2 id=&quot;tl-dr&quot;&gt;TL;DR&lt;a class=&quot;zola-anchor&quot; href=&quot;#tl-dr&quot; aria-label=&quot;Anchor link for: tl-dr&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Don&#x27;t use regular expressions for parsing&lt;&#x2F;li&gt;
&lt;li&gt;Parser combinators are a way to construct composable computations with higher-order functions
&lt;ul&gt;
&lt;li&gt;Examples:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;many1(digit1)&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;alt((tag(&amp;quot;hello&amp;quot;), tag(&amp;quot;sveiki&amp;quot;)))&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;pair(description, preceded(space0, tags))&lt;&#x2F;code&gt; &lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Parser combinators are easy to use to get results quickly&lt;&#x2F;li&gt;
&lt;li&gt;They are sufficient for 99% of pragmatic uses, falling short only if your library&#x27;s sole purpose is parsing&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;role-of-parsing-in-computing&quot;&gt;Role of parsing in computing&lt;a class=&quot;zola-anchor&quot; href=&quot;#role-of-parsing-in-computing&quot; aria-label=&quot;Anchor link for: role-of-parsing-in-computing&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Data processing is a pillar of computing.
To run an algorithm, one must first build up some data structures in memory.
The way to populate data structures is to get some raw data and load it into memory.
Data scientists work with raw data, clean it and create well-formatted data sets.
Programming language designers tokenise source code files and then parse those into abstract syntax trees.
Web-scraper author navigates scraped HTML and extracts values of interest.&lt;&#x2F;p&gt;
&lt;p&gt;Informally, each of these steps can be called &amp;quot;parsing&amp;quot;.
This post talks about how to do  &lt;em&gt;complete, composable and correct parsing in anger&lt;&#x2F;em&gt;.
What do we mean by this?&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Parsing in anger&lt;&#x2F;em&gt; considers the problem of data transformation pragmatically. A theoretically optimal solution is not required. Instead, the goal is to write a correct parser as quickly as possible.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;em&gt;Composable parsing&lt;&#x2F;em&gt; means that the resulting parser may consist of &amp;quot;smaller&amp;quot; components. It can itself be later on used as a component in &amp;quot;bigger&amp;quot; parsers.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;em&gt;Complete parsing&lt;&#x2F;em&gt; means that the input shall be consumed entirely. If the input can have any deviations or errors, its author shall encode them in the resulting parser.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;So how do we achieve it? Let&#x27;s first talk about how to &lt;em&gt;not&lt;&#x2F;em&gt; do it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;forget-about-regular-expressions&quot;&gt;Forget about regular expressions&lt;a class=&quot;zola-anchor&quot; href=&quot;#forget-about-regular-expressions&quot; aria-label=&quot;Anchor link for: forget-about-regular-expressions&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Thanks to the popularity of now perished Perl programming language, a whole generation of computer programmers was making &lt;a href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;1732348&#x2F;regex-match-open-tags-except-xhtml-self-contained-tags&#x2F;1732454#1732454&quot;&gt;futile attempts to parse non-regular languages with regular expressions&lt;&#x2F;a&gt;.
Regular expressions are no more than encodings of finite-state automata.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;ctf.cdn.doma.dev&#x2F;regex-is-automaton.jpg&quot; alt=&quot;An example finite state automaton, demonstrating &#x2F;^(0*1+)+$&#x2F; JavaScript regex&quot; &#x2F;&gt;
&lt;em&gt;Items over arrows are characters of {0, 1} alphabet. Circles are states, q1 is &amp;quot;accepting state&amp;quot;. Arrows denote state transitions.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Non-deterministic finite-state automata can rather elegantly accept many non-trivial languages.
Classical example is that no regular expression exists that accepts strings of form &amp;quot;ab&amp;quot;, &amp;quot;aabb&amp;quot;, &amp;quot;aaabbb&amp;quot;, ...
Equivalently, one can&#x27;t solve the matching parentheses problem with a regular expression. The simplest stack machine is needed for that.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;ctf.cdn.doma.dev&#x2F;balanced-parentheses.jpg&quot; alt=&quot;A sketch of a non-deterministic stack automaton that solves matching parentheses problem.&quot; &#x2F;&gt;
&lt;em&gt;Stack automaton can be in several states at once. A state with no transitions &amp;quot;fizzles&amp;quot; on any input. &lt;code&gt;(@\*&lt;&#x2F;code&gt; matches character &#x27;&lt;code&gt;(&lt;&#x2F;code&gt;&#x27; with any stack state. &lt;code&gt;ε@ε&lt;&#x2F;code&gt; matches instantaneously as the automaton gets to state p, but only if the stack is empty. &lt;a href=&quot;https:&#x2F;&#x2F;blackwells.co.uk&#x2F;bookshop&#x2F;product&#x2F;Introduction-to-Automata-Theory-Languages-and-Computation-by-John-E-Hopcroft-author-Rajeev-Motwani-author-Jeffrey-D-Ullman-author&#x2F;9781292039053&quot;&gt;The best introductory book for those interested in formal languages&lt;&#x2F;a&gt;.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Thus, regular expressions are nowhere close to providing enough facilities to work with context-free grammars.
But they may be sufficiently powerful to clean data or extract some values, so why are we saying you shouldn&#x27;t use them ever?
Practicality reasons!&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s take an example from some Regex Cookbook post (&lt;a href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;factory-mind&#x2F;regex-cookbook-most-wanted-regex-aa721558c3c1&quot;&gt;medium-paywalled link&lt;&#x2F;a&gt;).
This way we know it&#x27;s an actual approach used in the industry.
Here is one of the regular expressions author offers:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;perl6&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-perl6 &quot;&gt;&lt;code class=&quot;language-perl6&quot; data-lang=&quot;perl6&quot;&gt;&lt;span&gt;^(((h..ps?|f.p):\&#x2F;\&#x2F;)?(?:([\w\-\.])+(\[?\.\]?)([\w]){2,4}|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\[?\.\]?){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)))*([\w\&#x2F;+=%&amp;amp;_\.~?\-]*)$
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Many can superficially understand what is going on here.
This regex seemingly has something to do with links, but even when we resort to &lt;a href=&quot;https:&#x2F;&#x2F;regex101.com&#x2F;r&#x2F;6qUtv2&#x2F;1&#x2F;&quot;&gt;automated explanation&lt;&#x2F;a&gt;, things don&#x27;t get much clearer.
Well, according to the author, this regex is supposed to detect &amp;quot;defanged&amp;quot; URLs.
Now let&#x27;s see all ways in which it and any other sufficiently large regular expression fail.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;It is wrong: it doesn&#x27;t match &lt;code&gt;https:&#x2F;&#x2F;​ctflearn​.​com​&#x2F;​&lt;&#x2F;code&gt; (notice zero-width spaces).&lt;&#x2F;li&gt;
&lt;li&gt;It requires external tokenising, so no plug-and-play: it doesn&#x27;t match &lt;code&gt;␣https:&#x2F;&#x2F;ctflearn.com&#x2F;&lt;&#x2F;code&gt; (notice leading space).&lt;&#x2F;li&gt;
&lt;li&gt;External tokenisation is specific to this expression: it doesn&#x27;t match &lt;code&gt;https:&#x2F;&#x2F;ctflearn.com,&lt;&#x2F;code&gt; (notice trailing comma).&lt;&#x2F;li&gt;
&lt;li&gt;It&#x27;s impossible to fix it: matching optional characters around each printable character would turn it from a large and poorly readable piece of code into a huge and completely unreadable one. Your brain wouldn&#x27;t even be able to guess &lt;code&gt;h..ps&lt;&#x2F;code&gt; and &lt;code&gt;f.p&lt;&#x2F;code&gt; bits.&lt;&#x2F;li&gt;
&lt;li&gt;It can&#x27;t be used to extract values. Regexps don&#x27;t &amp;quot;parse data into data structures&amp;quot;. Rather they accept or decline strings. Thus, additional post-processing is required to make use of their output.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Regular expressions have intrinsic problems.
To us, it means that only short expressions should be used.
The author uses them exclusively with &lt;code&gt;grep&lt;&#x2F;code&gt;, &lt;code&gt;find&lt;&#x2F;code&gt;, and &lt;code&gt;vim&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;These days, gladly, a better parsing methodology becomes mainstream with working libraries in all the popular languages.
As you can guess from the title, it&#x27;s called &amp;quot;parser combinators&amp;quot;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;step-by-step-guide-to-composable-parsing&quot;&gt;Step-by-step guide to composable parsing&lt;a class=&quot;zola-anchor&quot; href=&quot;#step-by-step-guide-to-composable-parsing&quot; aria-label=&quot;Anchor link for: step-by-step-guide-to-composable-parsing&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;In the spirit of our previous blogs, let&#x27;s solve some practical task.
Consider you have to write an interactive TODO application, the pinnacle of practicality.
It specifies the following commands:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;add ${some word}* ${some #hashtag}*&lt;&#x2F;code&gt; (appends item ID)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;done ${some item ID}&lt;&#x2F;code&gt; (marks entry at item ID as resolved)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;search ${some word or some #hashtag}+&lt;&#x2F;code&gt; (searches across entries, returns a list of matching item IDs)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Let&#x27;s first define how will we represent parsed data, omitting the boring bits:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;enum &lt;&#x2F;span&gt;&lt;span&gt;Entry &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    Done (Index),
&lt;&#x2F;span&gt;&lt;span&gt;    Add (Description, &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;Vec&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;Tag&amp;gt;),
&lt;&#x2F;span&gt;&lt;span&gt;    Search (SearchParams),
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now let&#x27;s use the &lt;code&gt;nom&lt;&#x2F;code&gt; library to enjoy expressive and declarative parsing.
It has or used to have macro API and function API.
Since in v5 of the library macro API was very glitchy, we shall use function API, which we have tested with v6.&lt;&#x2F;p&gt;
&lt;p&gt;We will be parsing the commands line by line.
Begin with &lt;em&gt;declaring&lt;&#x2F;em&gt; the top-level parse for a line and meet your first parser combinator: &lt;code&gt;alt&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#50fa7b;&quot;&gt;command&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ffb86c;&quot;&gt;input&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span&gt;) 
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;-&amp;gt; IResult&amp;lt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;, Entry&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;&#x2F;* A *&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;alt&lt;&#x2F;span&gt;&lt;span&gt;((done, add, search))(input) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;&#x2F;* B *&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In &lt;code&gt;(A)&lt;&#x2F;code&gt; is declared that our function &lt;code&gt;command&lt;&#x2F;code&gt; is a parser.
&lt;a href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;nom&#x2F;6.1.2&#x2F;nom&#x2F;type.IResult.html&quot;&gt;&lt;code&gt;IResult&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; captures parsed type (in our case, &lt;code&gt;str&amp;amp;&lt;&#x2F;code&gt;) and output data structure (in our case, &lt;code&gt;Entry&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;In &lt;code&gt;(B)&lt;&#x2F;code&gt; we combine three parsers: &lt;code&gt;add&lt;&#x2F;code&gt;, &lt;code&gt;done&lt;&#x2F;code&gt;, and &lt;code&gt;search&lt;&#x2F;code&gt; with &lt;a href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;nom&#x2F;6.1.2&#x2F;nom&#x2F;branch&#x2F;fn.alt.html&quot;&gt;&lt;code&gt;nom::branch::alt&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; combinator.
It attempts to apply each of these parsers starting from the leftmost until one succeeds.&lt;&#x2F;p&gt;
&lt;p&gt;Now, let&#x27;s have a look at the simplest parser out of the three:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#50fa7b;&quot;&gt;done&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ffb86c;&quot;&gt;input&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;-&amp;gt; IResult&amp;lt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;, Entry&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;let &lt;&#x2F;span&gt;&lt;span&gt;(rest, value) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;preceded&lt;&#x2F;span&gt;&lt;span&gt;( &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;&#x2F;* A *&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;pair&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;tag&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;done&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;), ws), &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;&#x2F;* B *&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;many1&lt;&#x2F;span&gt;&lt;span&gt;(digit1) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;&#x2F;* C *&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;    )(input)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span&gt;; 
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;Ok&lt;&#x2F;span&gt;&lt;span&gt;((
&lt;&#x2F;span&gt;&lt;span&gt;      rest,
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#66d9ef;&quot;&gt;Entry&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#ff79c6;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;Done( &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;&#x2F;* D *&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#66d9ef;&quot;&gt;Index&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#ff79c6;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;new( &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;vec_to_u64&lt;&#x2F;span&gt;&lt;span&gt;(value) )
&lt;&#x2F;span&gt;&lt;span&gt;      ) 
&lt;&#x2F;span&gt;&lt;span&gt;    ))
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The first combinator we see straight away is &lt;code&gt;preceded&lt;&#x2F;code&gt;.
It forgets parse &lt;code&gt;(B)&lt;&#x2F;code&gt; and keeps only the output of &lt;code&gt;(C)&lt;&#x2F;code&gt;.
&lt;code&gt;(B)&lt;&#x2F;code&gt; still will consume input, however!
Generally speaking, it &lt;em&gt;combines&lt;&#x2F;em&gt; two computations into a composition that runs both of them, returning what the second one returns.
It is not the same as just running them in a sequence because here we &lt;em&gt;build up a computation&lt;&#x2F;em&gt;, but we will run it later on!&lt;&#x2F;p&gt;
&lt;p&gt;Interestingly, if we were writing Haskell we wouldn&#x27;t find &amp;quot;preceded&amp;quot; combinator in our &lt;a href=&quot;https:&#x2F;&#x2F;markkarpov.com&#x2F;tutorial&#x2F;megaparsec.html&quot;&gt;parser library&lt;&#x2F;a&gt;.
The reason is that what we described in the previous paragraph is called &amp;quot;right applicative arrow&amp;quot;, or, as was coined during Ben Clifford&#x27;s &lt;a href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=r_Enynu_TV0&quot;&gt;wonderful talk&lt;&#x2F;a&gt; &amp;quot;right &lt;em&gt;sparrow&lt;&#x2F;em&gt;&amp;quot;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;haskell&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-haskell &quot;&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span&gt;λ&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;&amp;gt; :&lt;&#x2F;span&gt;&lt;span&gt;t &lt;&#x2F;span&gt;&lt;span style=&quot;color:#50fa7b;&quot;&gt;(*&amp;gt;)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#50fa7b;&quot;&gt;(*&amp;gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;:: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bd93f9;&quot;&gt;Applicative&lt;&#x2F;span&gt;&lt;span&gt; f &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;=&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; f a &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; f b &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; f b
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The other two combinators are pretty self-explanatory.
&lt;code&gt;pair&lt;&#x2F;code&gt; combines parsers into a sequence, with the &lt;code&gt;ws&lt;&#x2F;code&gt; parser being a parser that consumes single whitespace. Here is a naive definition of &lt;code&gt;ws&lt;&#x2F;code&gt;: &lt;code&gt;one_of(&amp;quot; \t&amp;quot;)&lt;&#x2F;code&gt;.
&lt;code&gt;many1&lt;&#x2F;code&gt; repeats a &lt;code&gt;digit1&lt;&#x2F;code&gt; parse at least one time to succeed. &lt;code&gt;digit1&lt;&#x2F;code&gt; is implemented in &lt;code&gt;nom&lt;&#x2F;code&gt; itself.&lt;&#x2F;p&gt;
&lt;p&gt;Now let&#x27;s solidify the understanding of how to make sure that our parsers can be used by others.&lt;&#x2F;p&gt;
&lt;p&gt;We have already discussed that to achieve that, we need to return &lt;code&gt;IResult&lt;&#x2F;code&gt;.
Now it&#x27;s time to remember that it&#x27;s still a &amp;quot;Result&amp;quot; type, so its constructors are still &lt;code&gt;Err&lt;&#x2F;code&gt; and &lt;code&gt;Ok&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Err&lt;&#x2F;code&gt; variant of Result is constructed via the &lt;code&gt;?&lt;&#x2F;code&gt; modifier, that passes any potential error arising in parse &lt;code&gt;(A)&lt;&#x2F;code&gt; through.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Ok&lt;&#x2F;code&gt; variant of Result is constructed in &lt;code&gt;(D)&lt;&#x2F;code&gt; by transforming &lt;code&gt;many1&lt;&#x2F;code&gt; output (which is a vector of digits) into an unsigned 64-bit integer. It&#x27;s done with &lt;code&gt;vec_to_u64&lt;&#x2F;code&gt; function, which is omitted for brevity.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The shape of &lt;code&gt;Ok&lt;&#x2F;code&gt; value for &lt;code&gt;IResult&amp;lt;in, out&amp;gt;&lt;&#x2F;code&gt; is &lt;code&gt;Ok((rest: in, value: out))&lt;&#x2F;code&gt;.
Here &lt;code&gt;rest&lt;&#x2F;code&gt; is the remaining input to be parsed, and &lt;code&gt;value&lt;&#x2F;code&gt; is the output result of the parser.
You can see that &lt;code&gt;preceded&lt;&#x2F;code&gt; parse in &lt;code&gt;(A)&lt;&#x2F;code&gt; followed the very same pattern.&lt;&#x2F;p&gt;
&lt;p&gt;Here are more advanced parsers, that should solidify your intuition about how to use parser combinators in anger:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#50fa7b;&quot;&gt;add&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ffb86c;&quot;&gt;input&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;-&amp;gt; IResult&amp;lt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;, Entry&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;{    
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;let &lt;&#x2F;span&gt;&lt;span&gt;(rest, (d, ts)) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;preceded&lt;&#x2F;span&gt;&lt;span&gt;( &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;&#x2F;* B *&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;pair&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;tag&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;add&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;), ws),                     
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;pair&lt;&#x2F;span&gt;&lt;span&gt;(description, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;preceded&lt;&#x2F;span&gt;&lt;span&gt;(space0, tags)) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;&#x2F;* A *&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;  )(input)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;Ok&lt;&#x2F;span&gt;&lt;span&gt;( (
&lt;&#x2F;span&gt;&lt;span&gt;    rest,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#66d9ef;&quot;&gt;Entry&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#ff79c6;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;Add( &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#66d9ef;&quot;&gt;Description&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#ff79c6;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;new(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;d), ts )
&lt;&#x2F;span&gt;&lt;span&gt;  ) )
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#50fa7b;&quot;&gt;search&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ffb86c;&quot;&gt;input&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;-&amp;gt; IResult&amp;lt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;, Entry&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;let &lt;&#x2F;span&gt;&lt;span&gt;(rest, mash) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;preceded&lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;pair&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;tag&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;search&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;), ws),
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;separated_list&lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;tag&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;),
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;alt&lt;&#x2F;span&gt;&lt;span&gt;((tag_contents, search_word)) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;&#x2F;* C *&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;    )
&lt;&#x2F;span&gt;&lt;span&gt;  )(input)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;Ok&lt;&#x2F;span&gt;&lt;span&gt;((rest, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;mash_to_entry&lt;&#x2F;span&gt;&lt;span&gt;(mash)))
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#50fa7b;&quot;&gt;mash_to_entry&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ffb86c;&quot;&gt;mash&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;Vec&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;SearchWordOrTag&amp;gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;-&amp;gt; Entry &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;&#x2F;* D *&#x2F;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;&#x2F;* ... *&#x2F; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Parsing with combinators is so self-descriptive, it&#x27;s hard to find things that need to be clarified, but here are a couple of highlights:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Repeat &lt;code&gt;preceded&lt;&#x2F;code&gt; to focus on the data you need to parse out, see &lt;code&gt;(A)&lt;&#x2F;code&gt; and binding in &lt;code&gt;(B)&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Sometimes, you have to parse heterogeneous lists of things. The best way to do that in our experience is to create a separate data type to enclose this heterogeneity (&lt;code&gt;SearchWordOrTag&lt;&#x2F;code&gt;, in our case) and then use &lt;code&gt;separated_list&lt;&#x2F;code&gt; parser over &lt;code&gt;alt&lt;&#x2F;code&gt; of options, like in &lt;code&gt;(C)&lt;&#x2F;code&gt;. Finally, when you have a vector of matches, you can fold it into a neater data structure as needed by using a conversion function (see &lt;code&gt;(D)&lt;&#x2F;code&gt;).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This should be enough guidance for you to start getting comfortable with this amazing combinator-based parsing methodology.
Here are some parting thoughts:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Pay close attention to whitespaces, which can be a little tricky, especially since we&#x27;re not aware of the automatic tokenisation option in nom.&lt;&#x2F;li&gt;
&lt;li&gt;Take a look at &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Geal&#x2F;nom&#x2F;blob&#x2F;master&#x2F;doc&#x2F;choosing_a_combinator.md&quot;&gt;choosing a combinator&lt;&#x2F;a&gt; documentation page for the version of nom you are using (NB! entries in this table are pointing to macro versions of combinators rather than function versions).&lt;&#x2F;li&gt;
&lt;li&gt;If you so choose, you can check out &lt;a href=&quot;https:&#x2F;&#x2F;git.sr.ht&#x2F;%7Ejonn&#x2F;todo-rs-public&#x2F;tree&#x2F;main&#x2F;item&#x2F;src&#x2F;parser.rs&quot;&gt;code truly written in anger&lt;&#x2F;a&gt;, which inspired the snippets in this blog post. The code is authored by Chris Höppner and Jonn Mostovoy.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;If parsing is not your product or the main purpose of your library, odds are, parser combinators shall be sufficiently expressive and sufficiently performant for your tasks.
We hope you liked this post and happy parsing!&lt;&#x2F;p&gt;
&lt;p&gt;If you have any questions, you can reach out to &lt;a href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;podmostom&quot;&gt;Jonn&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;polastasule&quot;&gt;Pola&lt;&#x2F;a&gt; directly.
Start the conversation in the comments of the mirrors of this article on &lt;a href=&quot;https:&#x2F;&#x2F;dev.to&#x2F;doma&#x2F;&quot;&gt;Dev.to&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;doma-dev.medium.com&#x2F;&quot;&gt;Medium&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Pattern matching in Rust and other imperative languages</title>
		<published>2021-03-18T07:28:17+00:00</published>
		<updated>2021-03-18T07:28:17+00:00</updated>
		<link href="https://doma.dev/blog/pattern-matching-in-rust/" type="text/html"/>
		<id>https://doma.dev/blog/pattern-matching-in-rust/</id>
		<content type="html">&lt;h2 id=&quot;tl-dr&quot;&gt;TL;DR&lt;a class=&quot;zola-anchor&quot; href=&quot;#tl-dr&quot; aria-label=&quot;Anchor link for: tl-dr&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Rust is an imperative language that has the most pattern-related language facilities
&lt;ul&gt;
&lt;li&gt;Has both shallow destructuring and deep destructuring&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;if let&lt;&#x2F;code&gt; matching form can be utilised to alleviate Rust&#x27;s lack multiple-head functions&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Python has the weakest support for pattern-related facilities but it&#x27;s about to change
&lt;ul&gt;
&lt;li&gt;Language support for pattern-matching included in alpha (Edit thanks to reddit)).&lt;&#x2F;li&gt;
&lt;li&gt;Has packing&#x2F;unpacking operators&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;JavaScript has a lot of pattern-related language features
&lt;ul&gt;
&lt;li&gt;Position-based destructuring for arrays and key-based for objects&lt;&#x2F;li&gt;
&lt;li&gt;Rest parameters, supporting destructuring&lt;&#x2F;li&gt;
&lt;li&gt;Shallow-copy spread operator&lt;&#x2F;li&gt;
&lt;li&gt;With support from Microsoft, Facebook and NPM, proper pattern-matching in JS is inevitable&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;C++ has powerful libraries for pattern matching. Language support is likely in C++23&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;All the time, ideas and approaches sift into the world of conventional programming languages world from the programming language theory research and functional programming world.
Even Excel has lambdas now!&lt;&#x2F;p&gt;
&lt;p&gt;In this post, we shall cover pattern matching in various imperative programming languages.
We shall help you adopt pattern matching techniques to boost the expressiveness and conciseness of your code.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;ctf.cdn.doma.dev&#x2F;linked&#x2F;visitor-cpp-pattern-matching.png&quot; alt=&quot;Example of pattern matching techniques being more optimal programming method from the latest C++ pattern matching proposal&quot; &#x2F;&gt;
&lt;em&gt;An example from a C++ evolution proposal.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pattern-matching-in-rust&quot;&gt;Pattern matching in Rust&lt;a class=&quot;zola-anchor&quot; href=&quot;#pattern-matching-in-rust&quot; aria-label=&quot;Anchor link for: pattern-matching-in-rust&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Rust has the most advanced and well-designed pattern system among all imperative languages.
Part of it, of course, can be attributed to the fact that developers of Rust had the luxury of building a language from the ground up.
But most significantly, it stems from the rigour and culture of design and development.&lt;&#x2F;p&gt;
&lt;p&gt;Pattern matching facilities in Rust language are almost as rich as in its older functional brother Haskell.
To learn about them along with us, first, consider the following task (inspired by a real-life use-case):&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Explore a non-strictly-structured JSON object where keys are species and values are sets of animals of these species.&lt;&#x2F;p&gt;
&lt;p&gt;If an animal&#x27;s coat is fur or feathers, it&#x27;s &lt;code&gt;Cute&lt;&#x2F;code&gt;, otherwise it&#x27;s &lt;code&gt;Weird&lt;&#x2F;code&gt;.
If a species is &amp;quot;aye-aye&amp;quot;, it&#x27;s &lt;code&gt;Endangered&lt;&#x2F;code&gt;.
There may be new criteria discovered later on that change categorisation of a particular animal or species.&lt;&#x2F;p&gt;
&lt;p&gt;Categorise animals with distinct &lt;code&gt;name&lt;&#x2F;code&gt;s found in the given data set!&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;So let&#x27;s start with encoding the categories:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;#[derive(Hash, Debug, PartialEq, Eq, PartialOrd, Ord)] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;&#x2F;* A *&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;enum &lt;&#x2F;span&gt;&lt;span&gt;Category &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  Cute,&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  Weird,&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  Endangered,&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;(A)&lt;&#x2F;code&gt; makes sure that Rust will order values from top to bottom, so that &lt;code&gt;Cute &amp;lt; Weird &amp;lt; Endangered&lt;&#x2F;code&gt;.
This ordering will be important later on.&lt;&#x2F;p&gt;
&lt;p&gt;Now to encode the rules from the task.
Since our JSON is unstructured, we can&#x27;t rely on any property existing, so we can&#x27;t safely &lt;code&gt;unwrap&lt;&#x2F;code&gt; or reliably coerce JSON to some data Rust data structure:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#50fa7b;&quot;&gt;cat_species&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ffb86c;&quot;&gt;v&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;str&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;-&amp;gt; Category &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;match&lt;&#x2F;span&gt;&lt;span&gt; v &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;aye-aye&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#66d9ef;&quot;&gt;Category&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#ff79c6;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;Endangered, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;&#x2F;* A *&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;_ =&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#66d9ef;&quot;&gt;Category&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#ff79c6;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;Cute, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;&#x2F;* B *&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Our first &lt;code&gt;match&lt;&#x2F;code&gt;! How exciting!
This match is equivalent to switching over contents of variable &lt;code&gt;v&lt;&#x2F;code&gt;, of course.
However, it offers more flexibility later on.
With the power of destructuring, we can match complex structures, not just single variables.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;(A)&lt;&#x2F;code&gt; shows how to match a literal value, &lt;code&gt;(B)&lt;&#x2F;code&gt; shows the &amp;quot;catch-all&amp;quot; clause.
This pattern match reads &lt;em&gt;species named &amp;quot;aye-aye&amp;quot; is endangered, other species are cute&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Now let&#x27;s have a look at how to write something more interesting:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#50fa7b;&quot;&gt;cat_animal_first_attempt&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ffb86c;&quot;&gt;v&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;Value) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;-&amp;gt; Category &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;match&lt;&#x2F;span&gt;&lt;span&gt; v[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;coat&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;as_str&lt;&#x2F;span&gt;&lt;span&gt;() &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;Some&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;fur&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;Some&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;feathers&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#66d9ef;&quot;&gt;Category&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#ff79c6;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;Cute,&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;_ =&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#66d9ef;&quot;&gt;Category&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#ff79c6;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;Weird,&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The rule of cuteness is satisfied, no unwrapping used.
There are also no &lt;em&gt;explicit checks&lt;&#x2F;em&gt; if the value has Some contents or it has None!
This listing confidently states: &lt;em&gt;animals with a fur coat or with a feather coat are cute, others are weird&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;But is this implementation good enough?
One can check by considering a rule getting added, just as requirements warned us:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Animals that have the albino mutation are &lt;code&gt;Endangered&lt;&#x2F;code&gt;. Otherwise, previous rules apply.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#50fa7b;&quot;&gt;cat_animal_first_attempt_1&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ffb86c;&quot;&gt;v&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;Value) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;-&amp;gt; Category &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; cat &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;= match&lt;&#x2F;span&gt;&lt;span&gt; v[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;coat&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;as_str&lt;&#x2F;span&gt;&lt;span&gt;() &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;&#x2F;* A *&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;Some&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;fur&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;Some&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;feathers&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#66d9ef;&quot;&gt;Category&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#ff79c6;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;Cute, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;&#x2F;* B *&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;_ =&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#66d9ef;&quot;&gt;Category&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#ff79c6;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;Weird,&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;match&lt;&#x2F;span&gt;&lt;span&gt; v[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;mutation&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;as_str&lt;&#x2F;span&gt;&lt;span&gt;() &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;Some&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;albino&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#66d9ef;&quot;&gt;Category&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#ff79c6;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;Endangered,&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;_ =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; cat&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The snippet became bulky and boilerplate-y...
We now have to thread some variable like in &lt;code&gt;(A)&lt;&#x2F;code&gt;.
We have to remember not to short-circuit computation in &lt;code&gt;(B)&lt;&#x2F;code&gt; by adding a &lt;code&gt;return&lt;&#x2F;code&gt; by accident.
In case an additional rule pops up, we will need to decide between mutable &lt;code&gt;cat&lt;&#x2F;code&gt; or versioned.&lt;&#x2F;p&gt;
&lt;p&gt;So is this it?
Pattern matching collapses the moment we need to capture some heterogeneous set of matches?
Not quite.
Let us introduce &lt;code&gt;if let&lt;&#x2F;code&gt; statement, made just for this sort of challenge:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#50fa7b;&quot;&gt;cat_animal&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ffb86c;&quot;&gt;v&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;Value) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;-&amp;gt; Category &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;let &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;Some&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;albino&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; v[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;mutation&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;as_str&lt;&#x2F;span&gt;&lt;span&gt;() &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#66d9ef;&quot;&gt;Category&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#ff79c6;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;Endangered&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;else if &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;let &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;Some&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;fur&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;Some&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;feathers&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;              &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; v[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;coat&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;as_str&lt;&#x2F;span&gt;&lt;span&gt;() &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#66d9ef;&quot;&gt;Category&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#ff79c6;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;Cute&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;else &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#66d9ef;&quot;&gt;Category&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#ff79c6;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;Weird&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now that&#x27;s more like it.
But wait, what does it mean?
As with other pattern matches, left hand side is a pattern (for instance, &lt;code&gt;Some(&amp;quot;albino&amp;quot;)&lt;&#x2F;code&gt;) and right hand side is value (for instance, &lt;code&gt;v[&amp;quot;mutation&amp;quot;].as_str()&lt;&#x2F;code&gt;).
A branch under &lt;code&gt;if&lt;&#x2F;code&gt; will get executed when and only when the LHS pattern shall match the RHS value.&lt;&#x2F;p&gt;
&lt;p&gt;Pattern matching with &lt;code&gt;if let&lt;&#x2F;code&gt; syntax makes us start with the most specific clause and fall through to less specific clauses in an unambiguous order, taking away excessive liberty and thus making the code less error-prone.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;putting-it-all-together&quot;&gt;Putting it all together&lt;a class=&quot;zola-anchor&quot; href=&quot;#putting-it-all-together&quot; aria-label=&quot;Anchor link for: putting-it-all-together&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#50fa7b;&quot;&gt;categorise&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ffb86c;&quot;&gt;data&lt;&#x2F;span&gt;&lt;span&gt;: HashMap&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;String&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;Vec&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;Value&amp;gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;-&amp;gt; HashMap&amp;lt;Category, &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;Vec&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;String&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;&amp;gt;&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;let &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span&gt; retval &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#66d9ef;&quot;&gt;HashMap&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#ff79c6;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;new();&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;(species, animals) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;in&lt;&#x2F;span&gt;&lt;span&gt; data &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; animal &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;in&lt;&#x2F;span&gt;&lt;span&gt; animals &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;let &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;Some&lt;&#x2F;span&gt;&lt;span&gt;(name) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;(animal[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;name&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;as_str&lt;&#x2F;span&gt;&lt;span&gt;()) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;{ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;&#x2F;* A *&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        retval&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;entry&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;max&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;cat_species&lt;&#x2F;span&gt;&lt;span&gt;(species&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;as_str&lt;&#x2F;span&gt;&lt;span&gt;()),&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;                     &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;cat_animal&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;animal))) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;&#x2F;* B *&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;or_insert&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;Vec&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#ff79c6;&quot;&gt;::&lt;&#x2F;span&gt;&lt;span&gt;new()) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;&#x2F;* C *&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;          &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;(name&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;to_string&lt;&#x2F;span&gt;&lt;span&gt;())&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  retval&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now that we have categorisation functions, we can proceed to categorise our data set.
If &lt;code&gt;(A)&lt;&#x2F;code&gt; &lt;code&gt;if let&lt;&#x2F;code&gt; match fails (current animal has no name supplied), we&#x27;ll move to the next iteration.
Not all the patterns have to have the catch-all arm.&lt;&#x2F;p&gt;
&lt;p&gt;Otherwise, the variable &lt;code&gt;name&lt;&#x2F;code&gt; will store the current animal&#x27;s name and we will chain some functions from a handy &lt;code&gt;HashMap&lt;&#x2F;code&gt; API.
In &lt;code&gt;(B)&lt;&#x2F;code&gt; we use the &lt;code&gt;Ord&lt;&#x2F;code&gt; instance of &lt;code&gt;Category&lt;&#x2F;code&gt; enum to determine the highest priority category between species-based categorisation and per-animal categorisation with &lt;code&gt;std::cmp::max&lt;&#x2F;code&gt; function.&lt;&#x2F;p&gt;
&lt;p&gt;Then &lt;code&gt;HashMap&lt;&#x2F;code&gt;&#x27;s &lt;code&gt;entry&lt;&#x2F;code&gt; returns the reference to the value under the category.
If there is None, &lt;code&gt;or_insert&lt;&#x2F;code&gt; in &lt;code&gt;(C)&lt;&#x2F;code&gt; inserts an empty vector and returns a reference to it.
Finally, we can push the name of the current animal to this vector, and it will appear in our mapping!&lt;&#x2F;p&gt;
&lt;p&gt;We hope that this guide provides a reasonable introduction to pattern matching in Rust.
See the full code of the example module &lt;a href=&quot;https:&#x2F;&#x2F;git.sr.ht&#x2F;%7Epola&#x2F;prismatic-vista&#x2F;tree&#x2F;b686d11c61ebe3971282fea89bffdec4bd4f8391&#x2F;item&#x2F;src&#x2F;aaa_filter_all_printings.rs#L23&quot;&gt;on sourcehut&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s finish the post with some information about pattern-related features of other popular imperative languages.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;patterns-in-modern-javascript&quot;&gt;Patterns in modern JavaScript&lt;a class=&quot;zola-anchor&quot; href=&quot;#patterns-in-modern-javascript&quot; aria-label=&quot;Anchor link for: patterns-in-modern-javascript&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;javascript&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-javascript &quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#50fa7b;&quot;&gt;foldAndDump &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ffb86c;&quot;&gt;path&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ffb86c;&quot;&gt;xs&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ffb86c;&quot;&gt;cutoffs&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;&#x2F;&#x2F; snip&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;c &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;of &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;cutoffs&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;&#x2F;&#x2F;snap&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;An old feature of ECMAScript, the JS standard called &amp;quot;rest parameters&amp;quot; &lt;code&gt;...cutoffs&lt;&#x2F;code&gt; will match arguments of a function beyond the second into an array called &lt;em&gt;cutoffs&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-javascript &quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;var &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;rs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[];&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;let &lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;printing&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;info&lt;&#x2F;span&gt;&lt;span&gt;] of&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;     &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;Object&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;entries&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;allPrintingsJson&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;#39;data&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;]))&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;rs&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;({ &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;info&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;_pv_set&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;printing &lt;&#x2F;span&gt;&lt;span&gt;});&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;When the ellipsis isn&#x27;t in the &lt;em&gt;argument list&lt;&#x2F;em&gt;, it means that we&#x27;re dealing with a newer feature called &amp;quot;spread syntax&amp;quot;. &lt;code&gt;...info&lt;&#x2F;code&gt; means &amp;quot;include &lt;code&gt;info&lt;&#x2F;code&gt; object as is&amp;quot;. Analogously, spread syntax can spread an enumerable object across arguments of a function call:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-javascript &quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;xs &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bd93f9;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bd93f9;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bd93f9;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;];&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#66d9ef;&quot;&gt;console&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8be9fd;&quot;&gt;log&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#50fa7b;&quot;&gt;sum&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;xs&lt;&#x2F;span&gt;&lt;span&gt;));&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Finally, there is unpacking, which is a pretty standard feature by now:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#282a36;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;&amp;gt; [a,b] = [1,2]&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;[ 1, 2 ]&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; {x,y} = {y: a, x: b}&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;{ y: 1, x: 2 }&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; {k,l} = {y: a, x: b}&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;{ y: 1, x: 2 }&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; [a,b,x,y,k,l]&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;[ 1, 2, 2, 1, undefined, undefined ]&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;packing-and-unpacking-in-python&quot;&gt;Packing and unpacking in Python&lt;a class=&quot;zola-anchor&quot; href=&quot;#packing-and-unpacking-in-python&quot; aria-label=&quot;Anchor link for: packing-and-unpacking-in-python&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;In modern Python, any iterable is unpackable:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#282a36;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; a, *b, c = {&amp;#39;hello&amp;#39;: &amp;#39;world&amp;#39;, 4: 2, &amp;#39;rest&amp;#39;: True, False: False}&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; a, b, c&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;(&amp;#39;hello&amp;#39;, [4, &amp;#39;rest&amp;#39;], False)&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;*&lt;&#x2F;code&gt; is analogous to JS&#x27;s ellipsis (&lt;code&gt;...&lt;&#x2F;code&gt;) operator.
It can collect some &amp;quot;the rest of the values&amp;quot;, but it can also work as a spread for iterables:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#282a36;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; print(*[1, 2, 3])&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;1 2 3&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Conversely, in spirit of Python, there&#x27;s a special case operator called &amp;quot;dictionary unpacking operator&amp;quot;.
It works very similar to spread operator:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#282a36;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; print({&amp;#39;x&amp;#39;: True, **{&amp;#39;y&amp;#39;: False}, **{&amp;#39;x&amp;#39;: False, &amp;#39;z&amp;#39;: True}})&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;{&amp;#39;x&amp;#39;: False, &amp;#39;y&amp;#39;: False, &amp;#39;z&amp;#39;: True}&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Rightmost spread precedes.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pack-your-bags-we-re-going-pattern-matching&quot;&gt;Pack your bags: we&#x27;re going pattern matching&lt;a class=&quot;zola-anchor&quot; href=&quot;#pack-your-bags-we-re-going-pattern-matching&quot; aria-label=&quot;Anchor link for: pack-your-bags-we-re-going-pattern-matching&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Every single language that is in active development is looking to adopt more and more features from functional languages, and pattern matching is no difference.&lt;&#x2F;p&gt;
&lt;p&gt;We&#x27;ll conclude this post with a list of languages that will adopt proper pattern matching, ranked by degree of our certainty in adoption.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;pattern-matching-in-python&quot;&gt;Pattern matching in Python&lt;a class=&quot;zola-anchor&quot; href=&quot;#pattern-matching-in-python&quot; aria-label=&quot;Anchor link for: pattern-matching-in-python&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;There were different proposals throughout the history of Python, but &lt;a href=&quot;https:&#x2F;&#x2F;www.python.org&#x2F;dev&#x2F;peps&#x2F;pep-0634&#x2F;&quot;&gt;PEP 634&lt;&#x2F;a&gt; got implemented&lt;&#x2F;li&gt;
&lt;li&gt;Alpha version of Python with &amp;quot;structural pattern matching&amp;quot; is &lt;a href=&quot;https:&#x2F;&#x2F;www.python.org&#x2F;downloads&#x2F;release&#x2F;python-3100a6&#x2F;&quot;&gt;available since March 1st&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;pattern-matching-in-c&quot;&gt;Pattern matching in C++&lt;a class=&quot;zola-anchor&quot; href=&quot;#pattern-matching-in-c&quot; aria-label=&quot;Anchor link for: pattern-matching-in-c&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;Pattern matching as seen in &lt;a href=&quot;http:&#x2F;&#x2F;www.open-std.org&#x2F;jtc1&#x2F;sc22&#x2F;wg21&#x2F;docs&#x2F;papers&#x2F;2020&#x2F;p1371r3.pdf&quot;&gt;this evolution document&lt;&#x2F;a&gt; is likely to land in C++23&lt;&#x2F;li&gt;
&lt;li&gt;While you wait, there&#x27;s always &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mpark&#x2F;patterns&quot;&gt;a library or two that does a reasonable job&lt;&#x2F;a&gt; mimicking the new standard&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;pattern-matching-in-javascript&quot;&gt;Pattern matching in JavaScript&lt;a class=&quot;zola-anchor&quot; href=&quot;#pattern-matching-in-javascript&quot; aria-label=&quot;Anchor link for: pattern-matching-in-javascript&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;Tied for the first place in &amp;quot;the most likely to adopt proper pattern matching&amp;quot;, JavaScript&#x27;s standard called &amp;quot;ECMAScript&amp;quot;, has &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tc39&#x2F;proposal-pattern-matching&quot;&gt;this proposal&lt;&#x2F;a&gt; backed by Microsoft, Facebook and NPM.&lt;&#x2F;li&gt;
&lt;li&gt;The proposal is thoroughly reviewed and was moved to &amp;quot;stage 1&amp;quot;, which puts the theoretical release of this feature in the 2023-2025 range.&lt;&#x2F;li&gt;
&lt;li&gt;You can check our maths by inspecting &lt;code&gt;git log&lt;&#x2F;code&gt;s in &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tc39&#x2F;proposals&#x2F;blob&#x2F;master&#x2F;finished-proposals.md&quot;&gt;completed proposals repository&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;The idea of pattern matching is to have a code execution branch based on patterns, instead of conditions.
Instead of trying to encode &lt;em&gt;properties of values&lt;&#x2F;em&gt; necessary for a code branch to get executed, programmers who use pattern-matching encode &lt;em&gt;how should values look like&lt;&#x2F;em&gt; for it to happen.
Thus, in imperative languages, pattern matching promises more expressive and declarative code compared to predicate statements such as &lt;code&gt;if&lt;&#x2F;code&gt; and &lt;code&gt;case&lt;&#x2F;code&gt;, bar some corner cases.&lt;&#x2F;p&gt;
&lt;p&gt;It might be a subtle difference, but once you get it, you add a very powerful way of expression to your arsenal.&lt;&#x2F;p&gt;
&lt;p&gt;We find that understanding these concepts is akin to the understanding of declarative vs imperative programming paradigms.
To those interested in the philosophy of the matter, we suggest finding a cosy evening to curl up with a cup of steaming drink and watch Kevlin Henney&#x27;s &amp;quot;declarative thinking, declarative practice&amp;quot; talk:&lt;&#x2F;p&gt;
&lt;iframe width=&quot;100%&quot; height=&quot;400&quot; src=&quot;https:&#x2F;&#x2F;www.youtube-nocookie.com&#x2F;embed&#x2F;nrVIlhtoE3Y&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen&gt;&lt;&#x2F;iframe&gt;
&lt;p&gt;&lt;em&gt;Kevlin Henney: Declarative Thinking, Declarative Practice. ACCU 2016. Non-tracking YouTube embed.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
</content>
	</entry>
	<entry xml:lang="en">
		<title>Erlang and GNU poke are (better than) hex editors</title>
		<published>2020-12-17T03:31:19+00:00</published>
		<updated>2021-03-05T00:00:00+00:00</updated>
		<link href="https://doma.dev/blog/binary-processing-erlang-gnu-poke/" type="text/html"/>
		<id>https://doma.dev/blog/binary-processing-erlang-gnu-poke/</id>
		<content type="html">&lt;h2 id=&quot;tl-dr&quot;&gt;TL;DR&lt;a class=&quot;zola-anchor&quot; href=&quot;#tl-dr&quot; aria-label=&quot;Anchor link for: tl-dr&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Simple binary patching and experimentation can be done with &lt;a href=&quot;https:&#x2F;&#x2F;sourceforge.net&#x2F;projects&#x2F;wxhexeditor&#x2F;&quot;&gt;&lt;code&gt;wxHexEditor&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Erlang and Elixir are the only general-purpose programming languages that allow for binary pattern-matching, and should be used for functional and declarative binary editing.&lt;&#x2F;li&gt;
&lt;li&gt;GNU poke is a domain-specific language for &amp;quot;poking at binaries&amp;quot;. Different binary units (bits, bytes, uints, ints, structs) are supported natively and a genius mapping operator removes a lot of boilerplate when it comes to reading data into semantic structures and writing data out to memory or files.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;There are different ways to structure data within a file.
In the age of web, the most prominent one is JSON, followed by middle-aged XML and configuration-oriented YAML.
Human-readable ways to structure data, however, are just one side of the spectrum.
The other side is pure binary data mapped to some data structures to be computer-readable.
Features like &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Bit_field#C_programming_language&quot;&gt;bit fields in C&lt;&#x2F;a&gt; enable humans to define such mappings, but they also serve as a way to decode said structures.
Wiki example, when &lt;a href=&quot;https:&#x2F;&#x2F;godbolt.org&#x2F;z&#x2F;eb7rEW&quot;&gt;compiled and disassembled&lt;&#x2F;a&gt; doesn&#x27;t mention &lt;code&gt;BoxProps&lt;&#x2F;code&gt; at all.
Only when we add a function like the one below is included in the source code, would compiler spare some instructions to figure out where to get desired bits from.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;C&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-C &quot;&gt;&lt;code class=&quot;language-C&quot; data-lang=&quot;C&quot;&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;bool &lt;&#x2F;span&gt;&lt;span style=&quot;color:#50fa7b;&quot;&gt;getShowBorder&lt;&#x2F;span&gt;&lt;span&gt;(BoxProps &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ffb86c;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;return&lt;&#x2F;span&gt;&lt;span&gt; x&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;show_border&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Packing bits into structures warrants a whole separate post, but it&#x27;s worth mentioning that bitfields is a controversial feature of C99 and many C developers suggest not using it in favor of using bitmaps and manually written packing &#x2F; unpacking functions.
One of the reasons for it is that it&#x27;s not defined how the compiler packs bitfields, which means in practice, that some compilers reorder under-octet bitfields for the sake of optimisations.&lt;&#x2F;p&gt;
&lt;p&gt;Traditionally, non-human readable data is explored using &lt;code&gt;hexdump&lt;&#x2F;code&gt; or, less commonly &lt;a href=&quot;http:&#x2F;&#x2F;wiki.christophchamp.com&#x2F;index.php?title=Xxd&quot;&gt;&lt;code&gt;xxd&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; to print as binary instead of hex.
Finally, there is &lt;code&gt;od&lt;&#x2F;code&gt; which defaults to decimal representation.
But what if we need to edit it slightly for &lt;a href=&quot;https:&#x2F;&#x2F;www.darkmidnight.co.uk&#x2F;2019&#x2F;01&#x2F;editing-game-saves-with-hex-editor.html&quot;&gt;experimentation&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;www.linkedin.com&#x2F;pulse&#x2F;how-fix-sql-database-using-hex-editor-priyanka-chouhan?articleId=6607494760926146560&quot;&gt;error correction&lt;&#x2F;a&gt; or &lt;a href=&quot;https:&#x2F;&#x2F;roderickshawngraham.medium.com&#x2F;an-introduction-to-hex-editing-for-cybercrime-investigators-15041a1f3911&quot;&gt;binary carving&lt;&#x2F;a&gt;?
There is no single traditional tool for binary editing, but there&#x27;s a range of tools, collectively called &lt;em&gt;hex editors&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;shortcomings-of-hex-editors&quot;&gt;Shortcomings of hex editors&lt;a class=&quot;zola-anchor&quot; href=&quot;#shortcomings-of-hex-editors&quot; aria-label=&quot;Anchor link for: shortcomings-of-hex-editors&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Sadly, most of readily available hex editors have two major shortcomings:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;They only work on bytes&lt;&#x2F;li&gt;
&lt;li&gt;They rarely handle huge binary files in a responsive way&lt;&#x2F;li&gt;
&lt;li&gt;Some of hex editors have stability issues, i.e. they crash a lot&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;The worst offenders for crashes are ghex and bless, with latter barely working at all.
Which is funny, because these two editors are frequently suggested as the best out there.&lt;&#x2F;p&gt;
&lt;p&gt;Due to these circumstances, it&#x27;s wise to stick to &lt;a href=&quot;https:&#x2F;&#x2F;sourceforge.net&#x2F;projects&#x2F;wxhexeditor&#x2F;&quot;&gt;&lt;code&gt;wxHexEditor&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; for very basic inspection&#x2F;interaction and neglect hex editors altogether when it comes to advanced processing.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;hands-on&quot;&gt;Hands on!&lt;a class=&quot;zola-anchor&quot; href=&quot;#hands-on&quot; aria-label=&quot;Anchor link for: hands-on&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Let&#x27;s say we want to extract 7-bit ASCII from &lt;a href=&quot;https:&#x2F;&#x2F;ctf.cdn.doma.dev&#x2F;LastBitOfEveryByteIsAGuest.ASCII&quot;&gt;this file&lt;&#x2F;a&gt;.
To do this we need to take the last bit of every byte and shove it in the back of this binary.
Here is a single-take attempt to do it with a hex editor:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;ctf.cdn.doma.dev&#x2F;hex_editors_are_hard.gif&quot; alt=&quot;A person using hex editor to shuffle some bits around and failing&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Even if one knows what to do, it&#x27;s less than trivial to not screw it up, especially while trying to save time on insertions of zeros.
However, a hex editor is a great instrument to quickly validate that the method works and move on to more automated tools.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;binary-processing-with-erlang&quot;&gt;Binary processing with Erlang&lt;a class=&quot;zola-anchor&quot; href=&quot;#binary-processing-with-erlang&quot; aria-label=&quot;Anchor link for: binary-processing-with-erlang&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;My favorite tool to do binary processing with is Erlang.
It has a minimalist Prolog-like syntax, but most importantly, &lt;a href=&quot;http:&#x2F;&#x2F;erlang.org&#x2F;doc&#x2F;man&#x2F;binary.html&quot;&gt;native support to work with binaries&lt;&#x2F;a&gt;, &lt;a href=&quot;http:&#x2F;&#x2F;erlang.org&#x2F;doc&#x2F;programming_examples&#x2F;bit_syntax.html&quot;&gt;bitstrings&lt;&#x2F;a&gt;, including &lt;a href=&quot;http:&#x2F;&#x2F;erlang.org&#x2F;doc&#x2F;reference_manual&#x2F;expressions.html#bit_syntax&quot;&gt;binary pattern matching (see &amp;quot;Examples&amp;quot; subsection)&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;To do with Erlang what we failed to do with hex editor, we will write the following program, following our hex editor attempt:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;erlang&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-erlang &quot;&gt;&lt;code class=&quot;language-erlang&quot; data-lang=&quot;erlang&quot;&gt;&lt;span style=&quot;color:#50fa7b;&quot;&gt;send_guest_bits_home&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ffb86c;&quot;&gt;A&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bd93f9;&quot;&gt;7&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ffb86c;&quot;&gt;G&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bd93f9;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ffb86c;&quot;&gt;Rest&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;binary&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;% (E)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  {&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ffb86c;&quot;&gt;Hosts&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ffb86c;&quot;&gt;Guests&lt;&#x2F;span&gt;&lt;span&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;% (A)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#50fa7b;&quot;&gt;send_guest_bits_home&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;Rest&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    { &amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;Hosts&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;bitstring&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bd93f9;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bd93f9;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;A&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bd93f9;&quot;&gt;7&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;% (B)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    , &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;case &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;Guests &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;of &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;% (F)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bd93f9;&quot;&gt;_&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;binary&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;    -&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;          &amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;Guests&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;binary&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#bd93f9;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bd93f9;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;G&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bd93f9;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;% (C)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bd93f9;&quot;&gt;_&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;bitstring&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;          &amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;Guests&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;bitstring&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;G&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bd93f9;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;% (D)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;end &lt;&#x2F;span&gt;&lt;span&gt;});&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We call seven-bit clusters &amp;quot;Hosts&amp;quot;, and the appended bits, that we need to send to the back &amp;quot;Guests&amp;quot;.&lt;&#x2F;p&gt;
&lt;p&gt;Here we use standard recursion with accumulator, which in our case is a tuple of &lt;code&gt;Hosts&lt;&#x2F;code&gt; and &lt;code&gt;Guests&lt;&#x2F;code&gt;.
We bind current values of accumulator in &lt;code&gt;(A)&lt;&#x2F;code&gt; and update them in &lt;code&gt;(B)&lt;&#x2F;code&gt; and &lt;code&gt;(C)&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;(D)&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;In &lt;code&gt;(E)&lt;&#x2F;code&gt;, we match first byte of challenge with variables &lt;code&gt;A&lt;&#x2F;code&gt; (7 bits), and &lt;code&gt;G&lt;&#x2F;code&gt; (1 bit), and the rest of challenge gets matched with variable &lt;code&gt;Rest&lt;&#x2F;code&gt;.
As you can see, in this context &lt;code&gt;X:N&lt;&#x2F;code&gt; syntax means &amp;quot;match &lt;code&gt;N&lt;&#x2F;code&gt; bits of some binary value with variable &lt;code&gt;X&lt;&#x2F;code&gt;&amp;quot;.
As opposed to a similar syntax you can see in &lt;code&gt;(B)&lt;&#x2F;code&gt; and &lt;code&gt;(C)&lt;&#x2F;code&gt;, where syntax &lt;code&gt;0:1&lt;&#x2F;code&gt; means &amp;quot;span decimal value &lt;code&gt;0&lt;&#x2F;code&gt; over &lt;code&gt;1&lt;&#x2F;code&gt; bits&amp;quot;.
We specify that &lt;code&gt;Rest&lt;&#x2F;code&gt; variable is &lt;code&gt;binary&lt;&#x2F;code&gt;, not &lt;code&gt;bitstring&lt;&#x2F;code&gt;, to make sure it&#x27;s byte-aligned.
If it was &lt;code&gt;bitstring&lt;&#x2F;code&gt;, it would mean that it may be any amount of bits large, even seven or one.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;Hosts&lt;&#x2F;code&gt; update happens in &lt;code&gt;(B)&lt;&#x2F;code&gt; is that we take seven bits, pad it with a single &lt;code&gt;0&lt;&#x2F;code&gt; on the left and shove into the end of the first element of accumulator.&lt;&#x2F;p&gt;
&lt;p&gt;Case statement in &lt;code&gt;(F)&lt;&#x2F;code&gt; checks if &lt;code&gt;Guests&lt;&#x2F;code&gt; accumulator variable is byte-aligned (its bit size is divisible by eight) or not.
If it is, next iteration of &lt;code&gt;Guests&lt;&#x2F;code&gt; accumulator will be padded with a 0-bit, as seen in &lt;code&gt;(C)&lt;&#x2F;code&gt;.
If it isn&#x27;t we just append the &amp;quot;guest bit&amp;quot; to &lt;code&gt;Guests&lt;&#x2F;code&gt; accumulator verbatim, as seen in &lt;code&gt;(D)&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;erlang&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-erlang &quot;&gt;&lt;code class=&quot;language-erlang&quot; data-lang=&quot;erlang&quot;&gt;&lt;span style=&quot;color:#50fa7b;&quot;&gt;send_guest_bits_home&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;lt;&amp;lt;&amp;gt;&amp;gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;% (A)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#6272a4;&quot;&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  {&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ffb86c;&quot;&gt;Hosts&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#ffb86c;&quot;&gt;Guests&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;Hosts&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;bitstring&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;Guests&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#8be9fd;&quot;&gt;bitstring&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;.&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Finally, in &lt;code&gt;(A)&lt;&#x2F;code&gt;, when the remaining set of bits is empty, we return concatenation of the two accumulator variables.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;erlang&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-erlang &quot;&gt;&lt;code class=&quot;language-erlang&quot; data-lang=&quot;erlang&quot;&gt;&lt;span style=&quot;color:#50fa7b;&quot;&gt;solve&lt;&#x2F;span&gt;&lt;span&gt;() -&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  {&lt;&#x2F;span&gt;&lt;span style=&quot;color:#bd93f9;&quot;&gt;ok&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;Chal&lt;&#x2F;span&gt;&lt;span&gt;} &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#66d9ef;&quot;&gt;file&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#ff79c6;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#50fa7b;&quot;&gt;read_file&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;LastBitOfEveryByteIsAGuest.ASCII&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    ),&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;Out &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ff79c6;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#50fa7b;&quot;&gt;send_guest_bits_home&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;Chal&lt;&#x2F;span&gt;&lt;span&gt;, {&amp;lt;&amp;lt;&amp;gt;&amp;gt;, &amp;lt;&amp;lt;&amp;gt;&amp;gt;}&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    ),&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#66d9ef;&quot;&gt;file&lt;&#x2F;span&gt;&lt;span style=&quot;text-decoration:underline;color:#ff79c6;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#50fa7b;&quot;&gt;write_file&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#f1fa8c;&quot;&gt;&amp;quot;LastBitOfEveryByteIsAGuest.txt&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;Out&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  ).&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;When we run it, we get the hidden message!&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#282a36;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ erl&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Erlang&#x2F;OTP 22 [erts-10.6.4] [source] [64-bit] ...&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Eshell V10.6.4  (abort with ^G)&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;1&amp;gt; c(solve).&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;solve.erl:2: Warning: export_all flag enabled ...&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;{ok,solve}&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;2&amp;gt; solve:solve().&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;ok&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;3&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;BREAK: (a)bort (c)ontinue (p)roc info (i)nfo (l)oaded&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;       (v)ersion (k)ill (D)b-tables (d)istribution&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;a&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Thu Mar 04 01:27:26:530089000 sweater@conflagrate ~&#x2F;gnu&#x2F;poke-1.0&#x2F;build&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;$ cat LastBitOfEveryByteIsAGuest.txt&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;doma{w4rm357_w3lcom3___t0___th15___bl0g}&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;At the time of publishing of this post I thought that there is no way to express binary literals in Erlang, like in Python &lt;code&gt;0b101 == 5&lt;&#x2F;code&gt;.
However, as Reddit user Gwaerondor &lt;a href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;erlang&#x2F;comments&#x2F;m1z7np&#x2F;using_erlang_as_a_functional_hex_editor&#x2F;gqgqhe2&#x2F;?utm_source=reddit&amp;amp;utm_medium=web2x&amp;amp;context=3&quot;&gt;pointed out&lt;&#x2F;a&gt;, it&#x27;s possible with &lt;code&gt;Radix#&lt;&#x2F;code&gt;-syntax: &lt;code&gt;2#101 == 5&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;gnu-poke&quot;&gt;GNU poke&lt;a class=&quot;zola-anchor&quot; href=&quot;#gnu-poke&quot; aria-label=&quot;Anchor link for: gnu-poke&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;In 2017, thirty one years after Erlang&#x27;s initial prototype, a tool whose sole purpose is working with structured binary data was conceived.
It&#x27;s called &lt;em&gt;&lt;a href=&quot;http:&#x2F;&#x2F;www.jemarch.net&#x2F;poke&quot;&gt;GNU poke&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;, and its v1 got released just &lt;a href=&quot;https:&#x2F;&#x2F;savannah.gnu.org&#x2F;forum&#x2F;forum.php?forum_id=9949&quot;&gt;several days ago&lt;&#x2F;a&gt;.
Let&#x27;s see how to use it for the same transformation:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;poke&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-poke &quot;&gt;&lt;code class=&quot;language-poke&quot; data-lang=&quot;poke&quot;&gt;&lt;span&gt;type I = struct {&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  uint&amp;lt;7&amp;gt; host;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  uint&amp;lt;1&amp;gt; guest;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;};&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;One of the biggest powers of GNU poke is that you can define a structure and map it to some data in one swift motion with &amp;quot;map&amp;quot; operator &lt;code&gt;@&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#282a36;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;$ .&#x2F;poke&#x2F;poke LastBitOfEveryByteIsAGuest.ASCII&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt; * snip *&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;(poke) I[] @ 0#B&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;[I {host=(uint&amp;lt;7&amp;gt;) 100,guest=(uint&amp;lt;1&amp;gt;) 1},&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt; ...,&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt; I {host=(uint&amp;lt;7&amp;gt;) 95,guest=(uint&amp;lt;1&amp;gt;) 1}]&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;I[] @ 0#B&lt;&#x2F;code&gt; means &amp;quot;map the contents of currently loaded IO space onto array of &lt;code&gt;I&lt;&#x2F;code&gt;s&amp;quot;.
Now let&#x27;s see how to write the solve script.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;poke&quot; style=&quot;background-color:#282a36;color:#f8f8f2;&quot; class=&quot;language-poke &quot;&gt;&lt;code class=&quot;language-poke&quot; data-lang=&quot;poke&quot;&gt;&lt;span&gt;fun solve = (I[] xs) bit: {&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  var fh =&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    open(&amp;quot;hosts.out&amp;quot;, IOS_F_READ | IOS_F_WRITE); &#x2F;* (D) *&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  var fg =&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    open(&amp;quot;guests.out&amp;quot;, IOS_F_READ | IOS_F_WRITE); &#x2F;* (E) *&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  var bitsWrote = 0;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  var bytesWrote = 0;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;  for (i in xs) {&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    if (bitsWrote % 8 == 0) {&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;      bit[] @ fg : bitsWrote#b =&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        [(0 as bit), i.guest];   &#x2F;* (B) *&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;      bitsWrote += 2;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    } else {&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;      bit[] @ fg : bitsWrote#b =&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        [i.guest];               &#x2F;* (C) *&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;      bitsWrote += 1;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;      byte[] @ fh : bytesWrote#B =&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        [ (0 as bit):::i.host ]; &#x2F;* (A) *&#x2F;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;      bytesWrote += 1;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    close(fh);&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    close(fg);&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    return 0;&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;An interesting part of this function is &lt;code&gt;(A)&lt;&#x2F;code&gt;, it uses binary concatenation operator &lt;code&gt;:::&lt;&#x2F;code&gt;. It can concatenate heterogenous binary data types like a bit and a 7-bit blob.&lt;&#x2F;p&gt;
&lt;p&gt;Then, &lt;code&gt;(B)&lt;&#x2F;code&gt; and &lt;code&gt;(C)&lt;&#x2F;code&gt; write out guest bits, following the same logic as in Erlang implementation.
This is a pretty dense construction though, so let&#x27;s read it together.
&lt;code&gt;bit[] @ fg : bitsWrote#b&lt;&#x2F;code&gt; reads &amp;quot;map an array of bits to &lt;code&gt;fg&lt;&#x2F;code&gt; with a &lt;em&gt;bit&lt;&#x2F;em&gt; offset of &lt;code&gt;bitsWrote&lt;&#x2F;code&gt;&amp;quot;.
Now on the right hand side there is a value that will get mapped, which in &lt;code&gt;(B)&lt;&#x2F;code&gt; is two bits: &lt;code&gt;0&lt;&#x2F;code&gt;-padding and the guest bit and in &lt;code&gt;(C)&lt;&#x2F;code&gt; just the guest bit.&lt;&#x2F;p&gt;
&lt;p&gt;Now the sadder bit is that &lt;code&gt;(D)&lt;&#x2F;code&gt; and &lt;code&gt;(E)&lt;&#x2F;code&gt;: these files need to exist and contain enough data to map the outputs of the program, otherwise when ran, one&#x27;ll get &lt;em&gt;EOF exception&lt;&#x2F;em&gt;.
Here&#x27;s how to run this solution:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#282a36;color:#f8f8f2;&quot;&gt;&lt;code&gt;&lt;span&gt;Fri Mar 05 23:10:22:029970500 sweater@conflagrate ~&#x2F;gnu&#x2F;poke-1.0&#x2F;build&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;$ echo -n &amp;quot;00000000000000000000000000000000000000000000000&amp;quot; &amp;gt; hosts.out&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Fri Mar 05 23:10:36:841098700 sweater@conflagrate ~&#x2F;gnu&#x2F;poke-1.0&#x2F;build&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;$ echo -n &amp;quot;00000000000000000000000000000000000000000000000&amp;quot; &amp;gt; guests.out&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Fri Mar 05 23:10:40:652833300 sweater@conflagrate ~&#x2F;gnu&#x2F;poke-1.0&#x2F;build&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;$ .&#x2F;poke&#x2F;poke LastBitOfEveryByteIsAGuest.ASCII&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;     _____&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt; ---&amp;#39;   __\_______&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;            ______)  GNU poke 1.0&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;            __)&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;           __)&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt; ---._______)&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Copyright (C) 2019-2021 The poke authors.&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;License GPLv3+: GNU GPL version 3 or later ...&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;This is free software: you are free to change and redistribute it.&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;There is NO WARRANTY, to the extent permitted by law.&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Powered by Jitter 0.9.258.&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Perpetrated by Jose E. Marchesi.&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;For help, type &amp;quot;.help&amp;quot;.&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Type &amp;quot;.exit&amp;quot; to leave the program.&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;(poke) .load solve.poke&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;(poke) var xs = I[] @ 0#B&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;(poke) solve(xs)&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;(uint&amp;lt;1&amp;gt;) 0&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;(poke)&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Fri Mar 05 23:11:25:337643300 sweater@conflagrate ~&#x2F;gnu&#x2F;poke-1.0&#x2F;build&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;$ cat hosts.out&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;doma{w4rm357_w3lcom3___t0___th15___000000000000&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;Fri Mar 05 23:11:30:513672000 sweater@conflagrate ~&#x2F;gnu&#x2F;poke-1.0&#x2F;build&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;$  cat guests.out&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;bl0g}000000000000000000000000000000000000000000&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h1 id=&quot;picking-the-right-tool-at-the-right-time&quot;&gt;Picking the right tool at the right time&lt;a class=&quot;zola-anchor&quot; href=&quot;#picking-the-right-tool-at-the-right-time&quot; aria-label=&quot;Anchor link for: picking-the-right-tool-at-the-right-time&quot;&gt;🔗&lt;&#x2F;a&gt;&lt;&#x2F;h1&gt;
&lt;p&gt;In conclusion, it seems like it&#x27;s wise to use&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;hex editors allow for quick manual exploration,&lt;&#x2F;li&gt;
&lt;li&gt;erlang allows to follow functional style better,&lt;&#x2F;li&gt;
&lt;li&gt;GNU poke is imperative and procedure-oriented, but gives
&lt;ul&gt;
&lt;li&gt;more flexibility in literal representations&lt;&#x2F;li&gt;
&lt;li&gt;allows for less boilerplate due to genius mapping operator&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Of course, you can use all three at different stages of your work with binaries.&lt;&#x2F;p&gt;
&lt;p&gt;Good luck with binary exploration and happy hacking!&lt;&#x2F;p&gt;
</content>
	</entry>
</feed>
