<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.2.0">Jekyll</generator><link href="https://blog.nyarlathotep.one/feed.xml" rel="self" type="application/atom+xml" /><link href="https://blog.nyarlathotep.one/" rel="alternate" type="text/html" /><updated>2021-08-07T13:19:42+02:00</updated><id>https://blog.nyarlathotep.one/feed.xml</id><title type="html">Alexandre Moine’s blog</title><subtitle>Yet Another Blog About Computer Science and Other Things</subtitle><entry><title type="html">Practical deforestation for fixed-point structures – introducing tungsten</title><link href="https://blog.nyarlathotep.one/2019/07/practical-deforestation-for-fixed-point-structures/" rel="alternate" type="text/html" title="Practical deforestation for fixed-point structures – introducing tungsten" /><published>2019-07-26T00:00:00+02:00</published><updated>2019-07-26T00:00:00+02:00</updated><id>https://blog.nyarlathotep.one/2019/07/practical-deforestation-for-fixed-point-structures</id><content type="html" xml:base="https://blog.nyarlathotep.one/2019/07/practical-deforestation-for-fixed-point-structures/">&lt;p&gt;This post introduces &lt;a href=&quot;https://github.com/nobrakal/tungsten&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tungsten&lt;/code&gt;&lt;/a&gt;, a minimalist library that provides deforestation &lt;em&gt;for free&lt;/em&gt; to any structure expressed as a fixed-point. It is proved using free theorems and tested using &lt;a href=&quot;https://github.com/nomeata/inspection-testing&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inspection-testing&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;I worked earlier this year on bringing deforestation specifically to &lt;a href=&quot;https://github.com/snowleopard/alga&quot;&gt;algebraic graphs&lt;/a&gt;, recounted in &lt;a href=&quot;/2018/09/rewrite-rules-and-a-specific-fold/&quot;&gt;this past blog post&lt;/a&gt;.
The whole process was basically copy-pasting things from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GHC.Base&lt;/code&gt; module that works on lists and adapting them to work on graphs.&lt;/p&gt;

&lt;p&gt;As my first-year professor once told me:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Never copy-paste code. If you copy-paste a line of code, you are either introducing a bug or missing an opportunity to generalize your program.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, as I was not introducing a bug, it seems that I was missing an opportunity to generalize these rules. The theory already showed that this was possible but there was no (known to me) usable implementation. As the title suggests, I came to writing &lt;a href=&quot;https://github.com/nobrakal/tungsten&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tungsten&lt;/code&gt;&lt;/a&gt;, a library (not yet on Hackage) that generalizes the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;foldr/build&quot;&lt;/code&gt; rule to every structure expressed as a fixed-point.&lt;/p&gt;

&lt;p&gt;This post will introduce (quickly) the three needed concepts (namely deforestation, fixed-point structures, and recursion schemes) and how to cook them to obtain cool results. If you are in a hurry and familiar with these concepts, jump to the &lt;a href=&quot;#the-rules&quot;&gt;core section&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;deforestation&quot;&gt;Deforestation&lt;/h2&gt;

&lt;p&gt;The concept of deforestation was introduced by Wadler in his paper &lt;a href=&quot;https://doi.org/10.1016/0304-3975(90)90147-A&quot;&gt;“Deforestation: transforming programs to eliminate trees”&lt;/a&gt;, in Theoretical Computer Science 73, 2 (1990), 231 – 248.&lt;/p&gt;

&lt;p&gt;It is the idea that, when working with “good” functions on recursive structures, one can often optimize their composition to avoid building intermediate structures.&lt;/p&gt;

&lt;p&gt;A typical example on lists is the expression:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;map f&lt;/code&gt; will destruct the original list and produce a new one, which will be destructed right away by the outer &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;map&lt;/code&gt;. Knowing the definition of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;map&lt;/code&gt;, it is easy to see that the above expression is equivalent to a more efficient one:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xs&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;that go through the list only once.&lt;/p&gt;

&lt;p&gt;Deforestation is implemented in GHC for functions working on lists using the &lt;a href=&quot;https://downloads.haskell.org/~ghc/8.6.5/docs/html/users_guide/glasgow_exts.html#rewrite-rules&quot;&gt;rewrite rules system&lt;/a&gt; (that is, the above optimization is made automatically by the compiler; see &lt;a href=&quot;/2018/07/ghc-one-compiler-to-rule-them-all/&quot;&gt;this previous blog post&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;However, the rewriting operation we made in this example do not depends on the list structure: we just used the fact that we knew how the list produced by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;map&lt;/code&gt; is made. This concept can be simply generalized to any recursive structure (as theoretically explained by Johann in &lt;a href=&quot;https://doi.org/10.1023/A:1022982420888&quot;&gt;“A Generalization of Short-Cut Fusion and Its Correctness Proof”&lt;/a&gt;, Higher-Order and Symbolic Computation (2002) 15: 273).&lt;/p&gt;

&lt;p&gt;Currently, if one wants to add deforestation to another structure (such as algebraic graphs) then he needs to add a new set of rules. This is boring, hard to maintain and complicated for a neophyte. The idea is instead to generalize the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;foldr/build&quot;&lt;/code&gt; rule to catch all these cases.&lt;/p&gt;

&lt;p&gt;Firstly, we need a way to think about recursive structures generically: this is made using fixed-points.&lt;/p&gt;

&lt;h2 id=&quot;the-fix-operator&quot;&gt;The Fix operator&lt;/h2&gt;

&lt;p&gt;A useful way to think about recursive structures is using &lt;a href=&quot;https://en.wikipedia.org/wiki/Fixed_point_(mathematics)&quot;&gt;fixed-points&lt;/a&gt;: they are really often used in mathematics and can be used for types. All the next section was made after the already mentioned &lt;a href=&quot;http://hackage.haskell.org/package/recursion-schemes&quot;&gt;recursion-schemes&lt;/a&gt; package.&lt;/p&gt;

&lt;p&gt;Let me jump right into the subject: the fixed-point operator in Haskell can be defined as:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;kr&quot;&gt;newtype&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Fix&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Fix&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Fix&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;You can find this definition in the &lt;a href=&quot;https://github.com/nobrakal/tungsten/blob/c37f20a0b29d3bf8606ef6d1781f327bd6a2e24e/src/Tungsten/Fix.hs&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Tungsten.Fix&lt;/code&gt;&lt;/a&gt; module.&lt;/p&gt;

&lt;h4 id=&quot;what-is-this-strange-thing&quot;&gt;What is this strange thing?&lt;/h4&gt;

&lt;p&gt;The constructor &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Fix&lt;/code&gt; is of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f (Fix f) -&amp;gt; Fix f&lt;/code&gt;: it basically “hides” a level of application of the base type. You can think &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Fix f&lt;/code&gt; as a type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f&lt;/code&gt; applied to itself indefinitely (this is exactly the usual mathematical definition of a fixed-point).&lt;/p&gt;

&lt;h4 id=&quot;how-the-hell-am-i-using-this&quot;&gt;How the hell am I using this?&lt;/h4&gt;

&lt;p&gt;The simplest thing here is to take an example (everything here can be found in the &lt;a href=&quot;https://github.com/nobrakal/tungsten/blob/c37f20a0b29d3bf8606ef6d1781f327bd6a2e24e/src/Tungsten/Structure/List.hs&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Tungsten.Structure.List&lt;/code&gt;&lt;/a&gt; module).&lt;/p&gt;

&lt;p&gt;Linked lists can be defined as:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;c1&quot;&gt;-- The factored-out recursive type for lists.&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ListF&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;NilF&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ConsF&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Eq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Show&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Functor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;-- Linked lists as a fixed-point.&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;List&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Fix&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;ListF&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;How is it working? The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ListF&lt;/code&gt; data represent the two constructors of lists: either the empty one (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NilF&lt;/code&gt;) or an element and something else (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ConsF&lt;/code&gt;), if you replace “something else” by another list, you have a linked list.&lt;/p&gt;

&lt;p&gt;For example&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;lst&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ListF&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;ListF&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;ListF&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;ListF&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;lst&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;ConsF&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;ConsF&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;ConsF&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NilF&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;-- ~= [1,2,3]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;So, all lists are in the fixed-point of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ListF&lt;/code&gt;, that is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;type List a = Fix (ListF a)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then, we can define:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;c1&quot;&gt;-- The empty list. Similar to &apos;Prelude.[]&apos; for Prelude lists.&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;List&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Fix&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NilF&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;-- The cons operator. Similar to &apos;Prelude.(:)&apos; for Prelude lists.&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;cons&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;List&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;List&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;cons&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Fix&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;ConsF&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;lst&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;List&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;lst&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cons&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cons&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cons&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;-- ~= [1,2,3]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Note that being a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;newtype&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Fix&lt;/code&gt; is optimized away at compile time: there will be no &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Fix&lt;/code&gt; references in the code produced by the simplifier. This is due to the great work of Breitner et al. described in &lt;a href=&quot;https://doi.org/10.1145/2692915.2628141&quot;&gt;“Safe Zero-cost Coercions for Haskell”&lt;/a&gt; 2014. SIGPLAN Not. 49, 9 (Aug. 2014), 189–202.&lt;/p&gt;

&lt;h2 id=&quot;recursion-schemes&quot;&gt;Recursion-schemes&lt;/h2&gt;

&lt;p&gt;Deforestation is about destruction. Consequently, the next question is: how do we destruct fixed-point structures?&lt;/p&gt;

&lt;h3 id=&quot;it-is-cata-strophic&quot;&gt;It is &lt;em&gt;cata&lt;/em&gt;-strophic&lt;/h3&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldr&lt;/code&gt; is a pretty general pattern (who didn’t write a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fold_tree&lt;/code&gt; or a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fold_my_custom_struct&lt;/code&gt; ?). It is so general that there is a whole theory behind this process: recursion-schemes. They were popularized by Meijer et al. in their famous &lt;a href=&quot;https://doi.org/10.1007/3540543961_7&quot;&gt;“Functional Programming with Bananas, Lenses, Envelopes and Barbed Wire”&lt;/a&gt;, in Hughes J. (eds) Functional Programming Languages and Computer Architecture. FPCA 1991.&lt;/p&gt;

&lt;p&gt;I am not going to explore them deeply, there is plenty of well-made blog posts about them and a beautiful library called, well, &lt;a href=&quot;http://hackage.haskell.org/package/recursion-schemes&quot;&gt;recursion-schemes&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Particularly, functions that “destruct recursively” (such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldr&lt;/code&gt; for lists) are called &lt;em&gt;catamorphisms&lt;/em&gt;. Having this vocabulary, the idea of deforestation can be (roughly) expressed as: if a structure is built &lt;em&gt;recursively&lt;/em&gt; and after destructed by a catamorphism, then the intermediate structure does not need to be built.&lt;/p&gt;

&lt;h3 id=&quot;catamorphisms-for-fixed-point-structures&quot;&gt;Catamorphisms for fixed-point structures&lt;/h3&gt;

&lt;p&gt;Catamorphisms for fixed-point types can be expressed using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cata&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;cata&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Functor&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Fix&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;It is simple to use. If you have a (non recursive) structure (of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f&lt;/code&gt;, for example &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ListF u v&lt;/code&gt;) and you want to destruct its fixed-point (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Fix f&lt;/code&gt;, for example &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;List u&lt;/code&gt;) to produce something of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a&lt;/code&gt;, you only have to give a function that performs one step of the recursion, that is a function of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f a -&amp;gt; a&lt;/code&gt; (for lists, that is a function of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ListF u a -&amp;gt; a&lt;/code&gt;).
One can think &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cata go&lt;/code&gt; as just a function replacing every occurrence of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Fix&lt;/code&gt; by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;go&lt;/code&gt; in a fixed-point structure.&lt;/p&gt;

&lt;p&gt;Note that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Functor&lt;/code&gt; instance is needed to perform recursion since we only know that the structure is a fixed-point, but we don’t have access to its constructors.&lt;/p&gt;

&lt;h4 id=&quot;an-example&quot;&gt;An example&lt;/h4&gt;

&lt;p&gt;As an example of a catamorphism, let us write the function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;elem :: Eq a =&amp;gt; a -&amp;gt; List a -&amp;gt; Bool&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;elem&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Eq&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;List&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Bool&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;elem&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cata&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;-- go :: ListF a Bool -&amp;gt; Bool&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NilF&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;False&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;ConsF&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;the-rules&quot;&gt;The rule(s)&lt;/h2&gt;

&lt;p&gt;(Disclaimer: I have removed all the INLINE pragmas and phase control to simplify the reading. Don’t hesitate to have a look at the code to see the details.)&lt;/p&gt;

&lt;p&gt;Ok, now, the cool (and new) part.&lt;/p&gt;

&lt;p&gt;The main idea is that one can abstract the build of a fixed-point structure with respect to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Fix&lt;/code&gt; (just like the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build&lt;/code&gt; function of lists abstract the two lists constructors, see &lt;a href=&quot;https://blog.nyarlathotep.one/2018/09/rewrite-rules-and-a-specific-fold/#the-build-function&quot;&gt;this previous blog post&lt;/a&gt;). Then, because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cata go&lt;/code&gt; is just replacing every occurrence of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Fix&lt;/code&gt; by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;go&lt;/code&gt; in the structure, the intermediate structure can be avoided.
This is done by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;buildR&lt;/code&gt;, which can be defined as:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;c1&quot;&gt;-- Type of arguments of &apos;buildR&apos;.&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Cata&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;forall&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;-- Defining a function in terms of &apos;buildR&apos; allows fusion if&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- this function is composed later with &apos;cata&apos;.&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;buildR&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Cata&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Fix&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;buildR&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Fix&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;forall&lt;/code&gt; guarantees that the rule is valid (see &lt;a href=&quot;https://github.com/nobrakal/tungsten/blob/c37f20a0b29d3bf8606ef6d1781f327bd6a2e24e/doc/validity.md&quot;&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;buildR&lt;/code&gt; abstracted &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Fix&lt;/code&gt;, we can then replace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Fix&lt;/code&gt; by a function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;go&lt;/code&gt; if the structure is destructed right away by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cata go&lt;/code&gt;.
This is exactly the purpose of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;cata/buildR&quot;&lt;/code&gt; rule:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;cp&quot;&gt;{-# RULES
&quot;cata/buildR&quot; forall (go :: t a -&amp;gt; a) (g :: Cata t).
  cata go (buildR g) = g go
 #-}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;With this single rule, deforestation is provided to every fixed-point structures.&lt;/p&gt;

&lt;h3 id=&quot;examples&quot;&gt;Examples&lt;/h3&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;foldr/map&quot;&lt;/code&gt; optimization is just a particular case of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;cata/buildR&quot;&lt;/code&gt; (that is, for example, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldr f z . map g&lt;/code&gt; will be optimized in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldr (f . g) z&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Here are the definitions (note that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldr&lt;/code&gt; is just &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cata&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;map&lt;/code&gt; is defined in terms of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;buildR&lt;/code&gt;):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;foldr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;List&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;foldr&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;z&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cata&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foldr_go&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;foldr_go&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NilF&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;z&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;foldr_go&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;ConsF&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;List&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;List&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buildR&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mapBody&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;mapBody&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
      &lt;span class=&quot;kr&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;map_go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
        &lt;span class=&quot;kr&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;of&lt;/span&gt;
          &lt;span class=&quot;kt&quot;&gt;NilF&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NilF&lt;/span&gt;
          &lt;span class=&quot;kt&quot;&gt;ConsF&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;ConsF&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;kr&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cata&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;map_go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xs&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Then we have:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;   &lt;span class=&quot;n&quot;&gt;foldr&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;z&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cata&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foldr_go&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buildR&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mapBody&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;-- Inlining of `foldr` and `map`&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mapBody&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foldr_go&lt;/span&gt;               &lt;span class=&quot;c1&quot;&gt;-- The &quot;cata/buildR&quot; rule&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;map_go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;                 &lt;span class=&quot;c1&quot;&gt;-- Inlining of `mapBody`&lt;/span&gt;
     &lt;span class=&quot;kr&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;of&lt;/span&gt;
       &lt;span class=&quot;kt&quot;&gt;NilF&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foldr_go&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NilF&lt;/span&gt;
       &lt;span class=&quot;kt&quot;&gt;ConsF&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foldr_go&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;ConsF&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;kr&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cata&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;map_go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xs&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;map_go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;                 &lt;span class=&quot;c1&quot;&gt;-- Inlining of `foldr_go`&lt;/span&gt;
     &lt;span class=&quot;kr&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;of&lt;/span&gt;
       &lt;span class=&quot;kt&quot;&gt;NilF&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;z&lt;/span&gt;
       &lt;span class=&quot;kt&quot;&gt;ConsF&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;
    &lt;span class=&quot;kr&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cata&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;map_go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xs&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foldr&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;z&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xs&lt;/span&gt;             &lt;span class=&quot;c1&quot;&gt;-- Identification&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h4 id=&quot;another-example&quot;&gt;Another example&lt;/h4&gt;

&lt;p&gt;Ok this is cool, but we already had all of this for classical lists (with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;foldr/build&quot;&lt;/code&gt; rule)! Here is an example with binary trees (you can find definitions in the &lt;a href=&quot;https://github.com/nobrakal/tungsten/blob/c37f20a0b29d3bf8606ef6d1781f327bd6a2e24e/src/Tungsten/Structure/Tree.hs&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Tungsten.Structure.Tree&lt;/code&gt;&lt;/a&gt; module).&lt;/p&gt;

&lt;p&gt;Ready? Let us work with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bind&lt;/code&gt; for binary trees.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;c1&quot;&gt;-- The &quot;factored-out&quot; recursive type for binary trees.&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;TreeF&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;EmptyF&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;LeafF&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NodeF&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Eq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Show&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Functor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;-- Binary trees expressed as a fixed-point.&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Tree&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Fix&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;TreeF&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;-- @bind@ for trees, defined in terms of &apos;buildR&apos; and &apos;cata&apos;.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- Good consumer and good producer.&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;bind&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Tree&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Tree&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Tree&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;bind&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buildR&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fix&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bind_go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;kr&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;of&lt;/span&gt;
      &lt;span class=&quot;kt&quot;&gt;EmptyF&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fix&apos;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;EmptyF&lt;/span&gt;
      &lt;span class=&quot;kt&quot;&gt;LeafF&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cata&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fix&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;
      &lt;span class=&quot;kt&quot;&gt;NodeF&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fix&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;NodeF&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cata&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bind_go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bind&lt;/code&gt; might seems strange, but if you replace &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fix&apos;&lt;/code&gt; by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Fix&lt;/code&gt;, all is normal (remember, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cata fix == id&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Then, the composition of several &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bind&lt;/code&gt; will be optimized using its associativity &lt;em&gt;without anything to do&lt;/em&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;dBind&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dBindR&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Tree&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Tree&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Tree&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Tree&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;dBind&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bind&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bind&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;dBindR&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bind&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bind&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;With the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cata/buildR&lt;/code&gt; rule, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dBind&lt;/code&gt; will produce the same Core code as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dBindR&lt;/code&gt;! &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dBindR&lt;/code&gt; is indeed faster than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dBind&lt;/code&gt; since the inner &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bind&lt;/code&gt; has direct access to the result of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f&lt;/code&gt; without going through the original structure.&lt;/p&gt;

&lt;h3 id=&quot;proof&quot;&gt;Proof&lt;/h3&gt;

&lt;p&gt;Is this optimization valid? Is it proved?&lt;/p&gt;

&lt;p&gt;The answer is &lt;em&gt;yes&lt;/em&gt;. You can find a more-or-less formal proof &lt;a href=&quot;https://github.com/nobrakal/tungsten/blob/c37f20a0b29d3bf8606ef6d1781f327bd6a2e24e/doc/validity.md&quot;&gt;in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tungsten&lt;/code&gt; repository&lt;/a&gt;. Warning, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;seq&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;undefined&lt;/code&gt; are not good friends here, and they can break the rule (as for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;foldr/build&quot;&lt;/code&gt;).&lt;/p&gt;

&lt;h3 id=&quot;another-rule&quot;&gt;Another rule&lt;/h3&gt;

&lt;p&gt;Now if there is &lt;em&gt;no&lt;/em&gt; rewriting? All expressions made with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;buildR&lt;/code&gt; might be rewritten to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cata Fix x&lt;/code&gt; which corresponds to a totally useless destruction/reconstruction of the structure.&lt;/p&gt;

&lt;p&gt;That is why &lt;a href=&quot;https://github.com/nobrakal/tungsten/blob/c37f20a0b29d3bf8606ef6d1781f327bd6a2e24e/src/Tungsten/Fix.hs&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Tungsten.Fix&lt;/code&gt;&lt;/a&gt; also provides another rule:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{-# RULE
-- We cannot target `Fix` since it will be optimized away
&quot;cata/id&quot;
  cata coerce = id
 #-}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The only difficult step is to see that, because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Fix&lt;/code&gt; is a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;newtype&lt;/code&gt;, the only way to target it is using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;coerce&lt;/code&gt; (from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Data.Coerce&lt;/code&gt;).&lt;/p&gt;

&lt;h3 id=&quot;tests&quot;&gt;Tests&lt;/h3&gt;

&lt;p&gt;All of this seems theoretically ok, but does the optimization actually occurs? To test that rules are correctly firing, I use the great &lt;a href=&quot;https://github.com/nomeata/inspection-testing&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inspection-testing&lt;/code&gt;&lt;/a&gt; package which allows comparing GHC’s Core code of two expressions. All examples presented in this post (and many more) are tested this way (you can see all tests &lt;a href=&quot;https://github.com/nobrakal/tungsten/blob/c37f20a0b29d3bf8606ef6d1781f327bd6a2e24e/test&quot;&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;This was pretty fun to write.&lt;/p&gt;

&lt;p&gt;Fortunately, there are many paths to explore:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The fusion for paramorphisms (aka. generalized catamorphisms) needs more work to be usable.&lt;/li&gt;
  &lt;li&gt;For the rules to fire, we need to INLINE pretty much everything. It may increase the size of compiled code. Maybe there is a way to avoid this.&lt;/li&gt;
  &lt;li&gt;There used to be a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldr2&lt;/code&gt; rule for functions that perform recursion on two lists simultaneously. Is it possible to write &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cata2&lt;/code&gt; and optimize its composition with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;buildR&lt;/code&gt;?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;thanks&quot;&gt;Thanks&lt;/h3&gt;

&lt;p&gt;Thanks to Andrey Mokhov who suggested the idea and proofread this article.&lt;/p&gt;</content><author><name></name></author><category term="Haskell" /><summary type="html">This post introduces tungsten, a minimalist library that provides deforestation for free to any structure expressed as a fixed-point. It is proved using free theorems and tested using inspection-testing.</summary></entry><entry><title type="html">Learn-ocaml code classification</title><link href="https://blog.nyarlathotep.one/2019/06/learnocaml-code-classification/" rel="alternate" type="text/html" title="Learn-ocaml code classification" /><published>2019-06-24T00:00:00+02:00</published><updated>2019-06-24T00:00:00+02:00</updated><id>https://blog.nyarlathotep.one/2019/06/learnocaml-code-classification</id><content type="html" xml:base="https://blog.nyarlathotep.one/2019/06/learnocaml-code-classification/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;I am currently doing a summer internship at &lt;a href=&quot;https://www.irif.fr/&quot;&gt;IRIF&lt;/a&gt; under the supervision of &lt;a href=&quot;http://yann.regis-gianas.org/&quot;&gt;Yann Régis-Gianas&lt;/a&gt; about &lt;a href=&quot;https://github.com/ocaml-sf/learn-ocaml&quot;&gt;Learn-OCaml&lt;/a&gt;. It is a great platform designed to learn the &lt;a href=&quot;https://ocaml.org&quot;&gt;OCaml language&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Professors are able to write exercises and grade them automatically by reasoning on the student’s code AST.&lt;/li&gt;
  &lt;li&gt;Students can experiment OCaml in their web-browser thanks to the &lt;a href=&quot;https://github.com/ocsigen/js_of_ocaml&quot;&gt;js-of-ocaml&lt;/a&gt; compiler and a nice UI. It means that grading is performed mostly on the student side, and the teacher can grade files himself only once when he is correcting student’s exercises.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One of my goals this month is to develop a tool to help teachers to determine how exercises were solved by students, that is, to identify “similar” codes, and split the whole exercise database into equivalence classes.&lt;/p&gt;

&lt;p&gt;The term “exercises” is quite vague, and for the sake of simplicity, we will consider all exercises as just “defining a function”.&lt;/p&gt;

&lt;h2 id=&quot;first-steps&quot;&gt;First steps&lt;/h2&gt;

&lt;p&gt;The first step is to divide answers by their automatic grade: 2 codes with different grades are certainly different. Note that we make the hypothesis that teachers have correctly written their tests (for example, they do not give a random mark for each exercise). If it is not the case, professors will have a bigger problem than partitioning code anyway.
Hence, we will focus on how to determine equivalence classes between codes &lt;em&gt;with the same grade&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;We have a very strong hypothesis:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;All codes are valid OCaml fragments: it is guaranteed that they pass the OCaml type-checker.&lt;/li&gt;
  &lt;li&gt;Every code has (almost) same semantics because they share the same grade.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because I am focusing on &lt;em&gt;how&lt;/em&gt; an exercise was solved, I have decided to study code’s Abstract Syntax Tree (AST). Indeed, it allows us to abstract from spaces and indentation differences between user codes, and will introduce some semantic into the analysis.&lt;/p&gt;

&lt;p&gt;The question becomes now: how do we identify two “similar” AST?&lt;/p&gt;

&lt;h3 id=&quot;lambda&quot;&gt;Lambda&lt;/h3&gt;
&lt;p&gt;Speaking of AST, it is important to say the language it represents. I choose not to work directly on the whole OCaml language, but on an intermediate language used in the compilation pipeline called Lambda. Mainly, Lambda is partially optimized (with inlining of some values, compiled pattern-matching…) and removes syntactic sugar (such as the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;function&lt;/code&gt; key-word), which allows us to abstract even more from the syntax and try to focus on semantic.&lt;/p&gt;

&lt;p&gt;Note that, to construct a Lambda expression from an OCaml parse-tree, we need to type-check it. This method is not available for all use-cases, but is fine here since all codes are guaranteed to type-check.&lt;/p&gt;

&lt;h2 id=&quot;applied-ast-fingerprinting&quot;&gt;Applied AST fingerprinting&lt;/h2&gt;

&lt;h3 id=&quot;a-cool-paper&quot;&gt;A cool paper&lt;/h3&gt;

&lt;p&gt;After some research on the Internet, I came across a cool paper: &lt;a href=&quot;https://hal-upec-upem.archives-ouvertes.fr/hal-00627811/document&quot;&gt;Syntax tree fingerprinting: a foundation for source code similarity detection&lt;/a&gt; by Michel Chilowicz, Étienne Duris and Gilles Roussel. 2009, hal-00627811.&lt;/p&gt;

&lt;p&gt;The technique presented is pretty simple, while very smart: just hash recursively the AST. It is fast and identical ASTs are guaranteed to share the same hash. But we are not very interested in the direct hash of the structure: for example, two students might have implemented the same code, but with different variable names: we still want to mark the two codes as similar.&lt;/p&gt;

&lt;p&gt;The whole point is to find a “good” hash function, that is a function that captures only the interesting part of the AST. The paper rightly suggests that this could be done simply by defining a recursive hash function which doesn’t take into account unneeded data (such as variable names), and only the “shape” of the AST (for example, by hashing a constant string for each node).&lt;/p&gt;

&lt;p&gt;In the next paragraph, I will explain what I understood of this paper; we enter after in an original work, about the choice of the clustering analysis of the obtained hashes and an analysis of this choice on a real-world example.&lt;/p&gt;

&lt;h3 id=&quot;a-story-of-sub-asts&quot;&gt;A story of sub-ASTs&lt;/h3&gt;

&lt;p&gt;Suppose that we have such a “good” hash function. It is still not sufficient, because some codes may share substantial sub-AST, but not be totally equal, and thus the two ASTs will have different hashes.
For example, we want to recognize that&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ocaml&quot; data-lang=&quot;ocaml&quot;&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;is very close to&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ocaml&quot; data-lang=&quot;ocaml&quot;&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;As suggested in the previously mentioned paper, a possible idea is to keep the hash of “big” sub-ASTs (where the weight of an AST is the number of nodes and leaves it has).&lt;/p&gt;

&lt;p&gt;Then, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hash&lt;/code&gt; function will now be of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hash : int -&amp;gt; (int * string) list&lt;/code&gt;: it takes a weight threshold, and for every node of the AST that is over the threshold, it keeps the weight plus the hash.&lt;/p&gt;

&lt;p&gt;The obtained list is after sorted. Because we made the hypothesis that all codes shared the same semantic, we want to identify two codes with a hash list that have the same elements but in a different order (for example, where the order of pattern-matching cases was not the same).&lt;/p&gt;

&lt;p&gt;To say it more clearly, we are not interested in little sub-AST &lt;em&gt;alone&lt;/em&gt; (because for example, a (partial) function application &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;( + ) 1&lt;/code&gt; does not give enough information), but in how they are composed (for example, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;map (( + ) 1) xs&lt;/code&gt;). Do not mistake yourself, we do not forget about little sub-AST: because the hash is computed recursively, their hash will be used to compute the hash of their parents. We just don’t take them into account when measuring the distance between two ASTs.&lt;/p&gt;

&lt;h2 id=&quot;clustering&quot;&gt;Clustering&lt;/h2&gt;

&lt;p&gt;We are now able to identify exactly similar ASTs (so, same ASTs up to variable names and syntactic sugar) because they will share the same hash list. But how do we identify “less exactly” similar ASTs, that is, to identify “close” ASTs?&lt;/p&gt;

&lt;p&gt;In a mathematical world, this starts by defining something like a &lt;em&gt;distance&lt;/em&gt; between two ASTs:&lt;/p&gt;

&lt;h4 id=&quot;a-possible-semimetric&quot;&gt;A possible semimetric&lt;/h4&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ocaml&quot; data-lang=&quot;ocaml&quot;&gt;&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sum_of_fst&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
  &lt;span class=&quot;nn&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fold_left&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;fun&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;acc&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;acc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;(* Note: None is used to represent infinity *)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;semimetric&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hash&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hash&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;is_intersection_empty&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hx&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hy&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;None&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Some&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sum_of_fst&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;symmetric_difference&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hx&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;There is two cases:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;If the intersection is empty, then the two set are declared infinitely distant.&lt;/li&gt;
  &lt;li&gt;Else, we sum the weight of all hashes in the symmetric difference (the &lt;em&gt;symmetric difference&lt;/em&gt; of two sets A and B is defined as: (A ∪ B) \ (A ∩ B))&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note that this semimetric is well-defined:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;distance x y = 0 &amp;lt;=&amp;gt; x = y&lt;/code&gt;, because the symmetric difference of two sets is the empty set if and only if the two sets are the same.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;distance x y = distance y x&lt;/code&gt;, because the symmetric difference is commutative.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The fact that our hash lists are sorted allows an implementation of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;symmetric_difference&lt;/code&gt; in linear time.&lt;/p&gt;

&lt;h4 id=&quot;meaning&quot;&gt;Meaning&lt;/h4&gt;

&lt;p&gt;What does this “distance” mean? If two ASTs don’t share at least a sub-AST, then they are totally distinct (ie. infinitely distant). Else, we see how many of sub-ASTs they share, compared to all their recorded sub-ASTs. If they share big sub-ASTs, then the sum of the weight of the symmetric difference will be small. Else, if they share only a little sub-AST, then the sum of the weight of the symmetric difference will be bigger.&lt;/p&gt;

&lt;h3 id=&quot;cluster-analysis&quot;&gt;Cluster analysis&lt;/h3&gt;

&lt;p&gt;Now that we have a “distance”, we want to group ASTs that are close of each-others. This operation is called a &lt;a href=&quot;https://en.wikipedia.org/wiki/Cluster_analysis&quot;&gt;cluster analysis&lt;/a&gt; of our hash lists.&lt;/p&gt;

&lt;p&gt;I chose to use a &lt;a href=&quot;https://en.wikipedia.org/wiki/Hierarchical_clustering&quot;&gt;hierarchical clustering&lt;/a&gt; (which produces a &lt;a href=&quot;https://en.wikipedia.org/wiki/Dendrogram&quot;&gt;dendrogram&lt;/a&gt;) because, mainly, we don’t know how many classes we will obtain, and classical algorithms such as &lt;a href=&quot;https://en.wikipedia.org/wiki/K-means_clustering&quot;&gt;k-means&lt;/a&gt; require this information.&lt;/p&gt;

&lt;p&gt;The idea is simple: start with every hash list as a class with a single element, then at each step, merge the two closest classes, if it is possible.&lt;/p&gt;

&lt;p&gt;The question is: “how do we determine the distance between two classes?”. There are several approaches, but I choose to use the maximum of the distances between 2 elements of the sets, that is, for two classes &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;X&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Y&lt;/code&gt;: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;max {distance x y | x ∈ X, y ∈ Y}&lt;/code&gt;. This is called a &lt;em&gt;complete-linkage clustering&lt;/em&gt;. If the maximum is infinite, then I choose not to merge the two classes.&lt;/p&gt;

&lt;p&gt;Mainly, this approach renders the idea that: “if there are two elements that don’t share at least one sub-AST, then the classes cannot be merged”.&lt;/p&gt;

&lt;p&gt;The clustering phase returns a list of binary trees representing the classes and how they were made. It allows the end-user to see the distance between two ASTs, and thus get an idea of how good is the relation linking two implementations in the same class.&lt;/p&gt;

&lt;h2 id=&quot;at-the-end&quot;&gt;At the end&lt;/h2&gt;

&lt;p&gt;Let me sum up the process:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;First, we split all codes by their grade.&lt;/li&gt;
  &lt;li&gt;Then, for each obtained class:
    &lt;ul&gt;
      &lt;li&gt;First we transform all codes into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lambda&lt;/code&gt; AST.&lt;/li&gt;
      &lt;li&gt;Then we hash all of these AST to obtain a list of hash of their sub-ASTs.&lt;/li&gt;
      &lt;li&gt;Then we make the classes using the presented hierarchical clustering.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is only one parameter that needs to be taken into account: the weight threshold for sub-ASTs&lt;/p&gt;

&lt;h2 id=&quot;some-results&quot;&gt;Some results&lt;/h2&gt;

&lt;p&gt;I have tested all of this on the exercises from 3rd year student’s first course of OCaml in my University (a course that I have followed myself this year). The weight threshold is relative to the whole AST weight, and after some experiments, setting it to 30% (that is, only keeping sub-ASTs that have a weight superior to 30% of the whole AST weight) gives good results.&lt;/p&gt;

&lt;p&gt;Of course, the results are normally nicely rendered into the Learn-OCaml UI. Here is a simplified version, where is displayed the code of one element in each sub-classes (constituted only of codes with the same hash, thus very close one of each other).&lt;/p&gt;

&lt;h3 id=&quot;rev&quot;&gt;Rev&lt;/h3&gt;
&lt;p&gt;One interesting exercise was to define &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rev : &apos;a list -&amp;gt; &apos;a list&lt;/code&gt; which is reversing a list.
My tool split 154 implementations (which all had 10 out of 10) into 9 classes, let us study the main ones:&lt;/p&gt;

&lt;h4 id=&quot;a-main-class-not-so-satisfying&quot;&gt;A main class not so satisfying&lt;/h4&gt;

&lt;p&gt;The biggest equivalence class has 85 students, split in 7 sub-classes. (The number next to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Node&lt;/code&gt; constructor is the actual distance between the two sub-classes).&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Node 352.
    &lt;ul&gt;
      &lt;li&gt;Leaf with 6 student(s):
        &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;let rec rev l = match l with
| [] -&amp;gt; []
| [a] -&amp;gt; a::[]
| a::b -&amp;gt; (rev b) @ [a]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;        &lt;/div&gt;
      &lt;/li&gt;
      &lt;li&gt;Leaf with 1 student(s)
        &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;let rec rev l = match l with
[] | [_] -&amp;gt; l
| t::q -&amp;gt; rev q@[t]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;        &lt;/div&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Node 299.
    &lt;ul&gt;
      &lt;li&gt;Node 254.
        &lt;ul&gt;
          &lt;li&gt;Node 246.
            &lt;ul&gt;
              &lt;li&gt;Leaf with 25 student(s)
                &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;let rec rev l =
match l with
[]-&amp;gt;[]
|a::q -&amp;gt; append (rev q) [a]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;                &lt;/div&gt;
              &lt;/li&gt;
              &lt;li&gt;Leaf with 1 student(s)
                &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;let rec rev l =
match l with
| [] -&amp;gt; l
| t::q -&amp;gt; append (rev q) [t]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;                &lt;/div&gt;
              &lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
          &lt;li&gt;Node 196.
            &lt;ul&gt;
              &lt;li&gt;Leaf with 49 student(s)
                &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;let rec rev l = match l with
|[] -&amp;gt; []
|h::t -&amp;gt; (rev t)@[h]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;                &lt;/div&gt;
              &lt;/li&gt;
              &lt;li&gt;Leaf with 2 student(s)
                &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;let rec rev l = match l with
|[]-&amp;gt;l
|t::l&apos; -&amp;gt; (rev l&apos;)@[t]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;                &lt;/div&gt;
              &lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;Leaf with 1 student(s)
        &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;let rec rev l =
match l with
|[]-&amp;gt;[]
|[e]-&amp;gt; l
|e::q -&amp;gt; append (rev q) [e]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;        &lt;/div&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I think we can say that the tool effectively captured “close” codes. Even if sometimes there is a not needed pattern-matching, or the use of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;append&lt;/code&gt; (a function defined in a prior exercise) instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@&lt;/code&gt;, the idea is the same.&lt;/p&gt;

&lt;p&gt;Note that such a result directly inform the teacher that he needs to explain more the time complexity of the concatenation of lists in his course :)&lt;/p&gt;

&lt;h4 id=&quot;a-second-class&quot;&gt;A second class&lt;/h4&gt;

&lt;p&gt;The second class is constituted of 38 students:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Node 102.
    &lt;ul&gt;
      &lt;li&gt;Leaf with 22 student(s)
        &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;let rev l =
let rec rev_acc acc = function
| [] -&amp;gt; acc
| hd::tl -&amp;gt; rev_acc (hd::acc) tl
in
rev_acc [] l
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;        &lt;/div&gt;
      &lt;/li&gt;
      &lt;li&gt;Leaf with 14 student(s
        &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;let rec rev ls =
let rec aux xs rs =
match xs with
| [] -&amp;gt; rs
| hd :: tl -&amp;gt; aux tl (hd :: rs)
in aux ls []
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;        &lt;/div&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Leaf with 2 student(s)&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;let rev l = match l with
    [] -&amp;gt; []
  | h :: q -&amp;gt; let rec aux new_l l = match l with
        [] -&amp;gt; new_l
      | h :: q -&amp;gt; aux (h :: new_l) q in aux [] l
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Again here, the tool captured the idea of an auxiliary function.&lt;/p&gt;

&lt;h4 id=&quot;the-others&quot;&gt;The others&lt;/h4&gt;

&lt;p&gt;The third class is constituted with 12 students who used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;List.rev&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;List.fold_left&lt;/code&gt;, and the 6 last of other solutions (mainly some variations, using local &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;let&lt;/code&gt; bindings, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;List.hd&lt;/code&gt; instead of a pattern-matching, &lt;em&gt;et caetera&lt;/em&gt;).&lt;/p&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;Obtained results are surprisingly good and I think that such a tool can help teachers in their work.&lt;/p&gt;

&lt;p&gt;There are many things to do:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The ideas presented here are (almost) purely syntactical and it would be great if we were able to, for example, distinguish the use of a function from the standard library and a function made by the student.&lt;/li&gt;
  &lt;li&gt;Another possibility is to develop an AI, trained by teachers, to refine the partitioning made. For example, a teacher could say: these two AST looks syntactically equivalent, but their semantic is not the same, and they should not be in the same class.&lt;/li&gt;
  &lt;li&gt;The implementation I made focus on one toplevel definition, thus it does not take into account auxiliary definition made outside of the function.&lt;/li&gt;
  &lt;li&gt;Other clustering approach can maybe give better results&lt;/li&gt;
  &lt;li&gt;A better study of the weight threshold could also help to optimize the results.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;thanks&quot;&gt;Thanks&lt;/h4&gt;

&lt;p&gt;I want to thank Yann Régis-Gianas for his proofreading and his wise advise on this article.&lt;/p&gt;</content><author><name></name></author><category term="Ocaml" /><summary type="html">Introduction</summary></entry><entry><title type="html">Paramorphisms fusion for algebraic graphs</title><link href="https://blog.nyarlathotep.one/2019/02/paramorphisms-fusion-for-algebraic-graphs/" rel="alternate" type="text/html" title="Paramorphisms fusion for algebraic graphs" /><published>2019-02-03T00:00:00+01:00</published><updated>2019-02-03T00:00:00+01:00</updated><id>https://blog.nyarlathotep.one/2019/02/paramorphisms-fusion-for-algebraic-graphs</id><content type="html" xml:base="https://blog.nyarlathotep.one/2019/02/paramorphisms-fusion-for-algebraic-graphs/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;Algebraic graphs are a wonderful structure to work with, and especially to learn optimization techniques!&lt;/p&gt;

&lt;p&gt;In this article, the goal is to optimize at compile-time the composition of some paramorphisms and homomorphisms of graphs (don’t worry with these barbaric terms, all of this is discussed below).&lt;/p&gt;

&lt;p&gt;If you never approached algebraic graphs, I suggest that you read &lt;a href=&quot;https://github.com/snowleopard/alga-paper&quot;&gt;the original paper&lt;/a&gt; by A. Mokhov, &lt;a href=&quot;https://nobrakal.github.io/alga-tutorial/&quot;&gt;my tutorial&lt;/a&gt; or just the &lt;a href=&quot;http://hackage.haskell.org/package/algebraic-graphs&quot;&gt;documentation on Hackage&lt;/a&gt; of Alga, the Haskell library that implements the idea.&lt;/p&gt;

&lt;h2 id=&quot;the-problem&quot;&gt;The problem&lt;/h2&gt;
&lt;h3 id=&quot;shortcut-deforestation&quot;&gt;Shortcut deforestation&lt;/h3&gt;

&lt;p&gt;This process is introduced in &lt;a href=&quot;https://www.microsoft.com/en-us/research/wp-content/uploads/2016/07/deforestation-short-cut.pdf&quot;&gt;“A Short Cut to deforestation”&lt;/a&gt; (by A. Gill, J. Launchbury and S. Peyton Jones). Basically, it is the idea that one can remove intermediate structures when working with “good functions” (functions that are preserving the structure of the object on which they are working on).&lt;/p&gt;

&lt;p&gt;For example, the expression&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;foldr&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;builds an intermediate (and unneeded) list: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;map&lt;/code&gt; will build a new list that will be destructed right away by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldr&lt;/code&gt;. It can be optimized (and &lt;a href=&quot;https://downloads.haskell.org/~ghc/8.6.2/docs/html/users_guide/glasgow_exts.html#list-fusion&quot;&gt;GHC does it&lt;/a&gt;) to&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;foldr&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Note that this is possible only because &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;map&lt;/code&gt; preserves the list structure.&lt;/p&gt;

&lt;p&gt;On algebraic graphs, we have an equivalent to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldr&lt;/code&gt; named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldg&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;kr&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;Empty&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Vertex&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Overlay&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Connect&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;foldg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;foldg&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Empty&lt;/span&gt;         &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Vertex&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Overlay&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Connect&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Consider the following expression&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;foldg&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f :: Graph a -&amp;gt; Graph b&lt;/code&gt; is an operation that &lt;em&gt;preserves the structure of the graph&lt;/em&gt; (mathematicians like to call this an &lt;em&gt;homomorphism&lt;/em&gt;) and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x&lt;/code&gt; is a graph.&lt;/p&gt;

&lt;p&gt;We are pretty much in the same situation as for lists: indeed, the above expression currently goes through the structure two times (one for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f&lt;/code&gt;, the other for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldg&lt;/code&gt;). The goal is to rewrite it to an equivalent expression that goes through the graph only once, using the fact that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f&lt;/code&gt; is an homomorphism.&lt;/p&gt;

&lt;h3 id=&quot;implementation-for-algebraic-graphs&quot;&gt;Implementation for algebraic graphs&lt;/h3&gt;

&lt;p&gt;I already wrote &lt;a href=&quot;https://blog.nyarlathotep.one/2018/09/rewrite-rules-and-a-specific-fold/&quot;&gt;about how I implemented this technique for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldg&lt;/code&gt; using GHC’s rewrite rules&lt;/a&gt;. I suggest that you read it to understand better the following, even if I will try to quickly summarize it just below.&lt;/p&gt;

&lt;h3 id=&quot;quick-reminder&quot;&gt;Quick reminder&lt;/h3&gt;

&lt;p&gt;The basic idea is to view a graph homomorphism as a function transforming arguments passed to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldg&lt;/code&gt; (which are generally graph constructors).&lt;/p&gt;

&lt;p&gt;First of all, we need to remember a cool result (proved in &lt;a href=&quot;https://blog.nyarlathotep.one/2018/12/algebraic-graphs-homomorphisms/&quot;&gt;this blog&lt;/a&gt;): graphs homomorphisms are exactly functions that are made with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bind&lt;/code&gt;, which is written for graphs as:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foldg&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Empty&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Overlay&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Connect&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;So we only have to optimize something like:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;foldg&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The question is: how to represent “functionally” the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bind&lt;/code&gt; operation? Remember, if we can represent &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bind&lt;/code&gt; as a function operating on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldg&lt;/code&gt; arguments, we can easily fuse it with an actual &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldg&lt;/code&gt;-function (imitating what GHC does for lists).&lt;/p&gt;

&lt;p&gt;First, there is a type that encapsulate this notion:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;kr&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Foldg&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;forall&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Then we can use these rules:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;buildR&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Foldg&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;buildR&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Empty&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Vertex&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Overlay&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Connect&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{-# INLINE [1] buildR #-}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;-- These rules transform functions into their buildR equivalents.&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{-# RULES
&quot;buildR/bindR&quot; forall f g.
bindR g f = buildR (\e v o c -&amp;gt; foldg e (foldg e v o c . f) o c g)

&quot;foldg/buildR&quot; forall e v o c (g :: Foldg a).
foldg e v o c (buildR g) = g e v o c
 #-}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;It effectively transforms any occurrence of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bind&lt;/code&gt; into a “function-like” foldg, that transforms its arguments.&lt;/p&gt;

&lt;p&gt;Then if we encounter an expression like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldg e v o c . buildR&lt;/code&gt;, we can optimize the composition using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;foldg/buildR&quot;&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;If there was nothing to optimize, things are rewritten back to their normal form with the inlining of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;buildR&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;hasedge&quot;&gt;hasEdge&lt;/h3&gt;

&lt;p&gt;We can now optimize the composition of several functions of the Alga library.&lt;/p&gt;

&lt;p&gt;Let me introduce a killjoy: the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hasEdge&lt;/code&gt; function, that tests if an edge is present in the graph. It is actually defined as:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;kr&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Hit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Miss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Tail&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Edge&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;deriving&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Eq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Ord&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;hasEdge&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Eq&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Bool&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;hasEdge&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hit&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Edge&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;hit&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Empty&lt;/span&gt;         &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Miss&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;hit&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Vertex&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Tail&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Miss&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;hit&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Overlay&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hit&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;of&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;Miss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hit&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;Tail&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Tail&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hit&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;Edge&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Edge&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;hit&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Connect&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hit&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;of&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;Miss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hit&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;Tail&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hasVertex&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Edge&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Tail&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;Edge&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Edge&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The algorithm is pretty simple:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;There is of course no edge in an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Empty&lt;/code&gt; graph, so you &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Miss&lt;/code&gt; it.&lt;/li&gt;
  &lt;li&gt;If you &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hit&lt;/code&gt; a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Vertex&lt;/code&gt; corresponding to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Tail&lt;/code&gt; of the edge, you say it, else you &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Miss&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;For an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Overlay&lt;/code&gt; node:
    &lt;ul&gt;
      &lt;li&gt;If you missed it in the left part, the edge can only be in the right one.&lt;/li&gt;
      &lt;li&gt;If you hit a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Tail&lt;/code&gt; in the left part, maybe there is the whole edge in the right part, but at least you hit the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Tail&lt;/code&gt;.&lt;/li&gt;
      &lt;li&gt;If you hit an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Edge&lt;/code&gt;, you say it!&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;For a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Connect&lt;/code&gt; node,
    &lt;ul&gt;
      &lt;li&gt;If you missed it in the left part, the edge can only be in the right one.&lt;/li&gt;
      &lt;li&gt;If you hit a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Tail&lt;/code&gt; in the left part:
        &lt;ul&gt;
          &lt;li&gt;If the right part contains the other part of the edge, you found the whole &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Edge&lt;/code&gt;.&lt;/li&gt;
          &lt;li&gt;Otherwise, you only have its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Tail&lt;/code&gt;.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;If you hit an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Edge&lt;/code&gt;, you say it!&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;observations&quot;&gt;Observations&lt;/h4&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hasEdge&lt;/code&gt; seems a bit like a foldg-function but not totally. The problem comes with the call to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hasVertex&lt;/code&gt; on an unconsumed part of the graph in the middle of the process.&lt;/p&gt;

&lt;p&gt;Our actual rules will &lt;em&gt;not&lt;/em&gt; optimize &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hasEdge (x &amp;gt;&amp;gt;= f)&lt;/code&gt;, since our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hasEdge&lt;/code&gt; is not expressed with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldg&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hasEdge&lt;/code&gt; seems anyway not so extraordinary and it is easy to see that it can be indeed optimized when used with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fmap&lt;/code&gt; to traverse the graph only once. For example &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hasEdge s t (fmap f g)&lt;/code&gt; is equivalent to:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;hasEdgeF&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Eq&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Bool&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;hasEdgeF&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Edge&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Empty&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Miss&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Vertex&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Tail&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Miss&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Overlay&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;of&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;Miss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;Tail&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Tail&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;Edge&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Edge&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Connect&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;of&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;Miss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;Tail&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foldg&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;False&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;||&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;||&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Edge&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Tail&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;Edge&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Edge&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Note that in this expression, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fmap&lt;/code&gt; operation was incorporated in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;go (Vertex x)&lt;/code&gt; &lt;em&gt;and&lt;/em&gt; in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hasVertex&lt;/code&gt; call (which was also inlined).&lt;/p&gt;

&lt;p&gt;Can the theory help us to optimize it automatically? And even better, for any function like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hasEdge&lt;/code&gt;, that are looking almost like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldg&lt;/code&gt; but not?&lt;/p&gt;

&lt;h2 id=&quot;more-theory&quot;&gt;More theory&lt;/h2&gt;

&lt;h3 id=&quot;of-bananas-and-barbed-wire&quot;&gt;Of bananas and barbed wire&lt;/h3&gt;

&lt;p&gt;The great article &lt;a href=&quot;https://maartenfokkinga.github.io/utwente/mmf91m.pdf&quot;&gt;“Functional Programming with Bananas, Lenses, Envelopes and Barbed Wire”&lt;/a&gt; of E. Meijer, M. Fokkinga and R. Paterson, describes some recursion operators; here, we will focus on two major: catamorphisms (written between bananas bracket in the article) and paramorphisms (written between barbed wire bracket in the article). If you haven’t read it, it is really worth it!&lt;/p&gt;

&lt;h4 id=&quot;catamorphisms&quot;&gt;Catamorphisms&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;Catamorphism&lt;/em&gt; (which comes from Greek “κατα” meaning “downwards”, “down from”) is a term to describe functions that:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;In functional programming, generalize the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fold&lt;/code&gt; function, that is, on a list, a function of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cata :: (a -&amp;gt; b -&amp;gt; b) -&amp;gt; b -&amp;gt; [a] -&amp;gt; b&lt;/code&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cata&lt;/code&gt; take a combination function, a base case, and fold the structure accordingly.&lt;/li&gt;
  &lt;li&gt;From a mathematical point of view, it (quoting the great &lt;a href=&quot;https://en.wikipedia.org/wiki/Catamorphism&quot;&gt;Wikipedia&lt;/a&gt;) “denotes the unique homomorphism from an initial algebra into some other algebra”. Here, the important word is, I think, “homomorphism”: being a homomorphism, a catamoprhism &lt;em&gt;will preserve the underlying algebraic structure&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You already know &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cata&lt;/code&gt; for lists; as a clever reader has already noticed from its type, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cata&lt;/code&gt; for lists is nothing more than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldr&lt;/code&gt; in disguise:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;cata&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;cata&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;combine&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;[]&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;cata&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;combine&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;combine&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cata&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;z&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Did you guess what is the function expressing a catamorphism on graph? It is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldg&lt;/code&gt;!&lt;/p&gt;

&lt;h4 id=&quot;paramorphisms&quot;&gt;Paramorphisms&lt;/h4&gt;

&lt;p&gt;Quoting again  &lt;a href=&quot;https://en.wikipedia.org/wiki/Paramorphism&quot;&gt;Wikipedia&lt;/a&gt;: “In formal methods of computer science, a paramorphism (from Greek παρά, meaning “close together”) is an extension of the concept of catamorphism […] to deal with a form which ‘eats its argument and keeps it too’”.&lt;/p&gt;

&lt;p&gt;The idea is to extend the combination function: you can allow it to reason on the structure itself. When you are doing recursion, you sometimes want to inspect (or directly use) what is left of the structure (note that you cannot simply do that in a catamorphism (since this argument is not available to the combination function)).&lt;/p&gt;

&lt;p&gt;For example, again on lists, you will have something like: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;para :: (a -&amp;gt; ([a], b) -&amp;gt; b) -&amp;gt; b -&amp;gt; [a] -&amp;gt; b&lt;/code&gt;. The combination function can use the &lt;em&gt;not already consumed&lt;/em&gt; list.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;para&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;para&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;combine&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;[]&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;para&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;combine&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;combine&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;para&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;z&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;blockquote&gt;
  &lt;p&gt;But why can I need such a function ? &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldr&lt;/code&gt; does already anything I want!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Indeed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldr&lt;/code&gt; is equivalent (in term of expressivity) to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;para&lt;/code&gt;. This is nicely explained in &lt;a href=&quot;https://stackoverflow.com/a/13317563&quot;&gt;this stackoverflow answer&lt;/a&gt;. Basically, you can define &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldr&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;para&lt;/code&gt; and you can define &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;para&lt;/code&gt; from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldr&lt;/code&gt;. But if you do it with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;para&apos;&lt;/code&gt; (again from the mentioned stackoverflow answer):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;para&apos;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;snd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foldr&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;\&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xs&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;para&apos;&lt;/code&gt; will be slower than the one we defined: it builds an exact copy of the list as it traverses it.&lt;/p&gt;

&lt;p&gt;So the answer to the above question is efficiency: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;para&lt;/code&gt; allows you to make more efficient functions, and when you work with graphs (and when you simply work), you just want the more efficient implementation!&lt;/p&gt;

&lt;h4 id=&quot;paramorphisms-for-graphs&quot;&gt;Paramorphisms for graphs&lt;/h4&gt;

&lt;p&gt;One can make paramorphisms for graphs by changing a bit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldg&lt;/code&gt; (and making more complex its signature):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;paragraph&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;paragraph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Empty&lt;/span&gt;         &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Vertex&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Overlay&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Connect&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;(Thanks Andrey for the great name :) ).&lt;/p&gt;

&lt;h3 id=&quot;back-to-hasedge&quot;&gt;Back to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hasEdge&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;You guessed it, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hasEdge&lt;/code&gt; is a paramorphism!&lt;/p&gt;

&lt;p&gt;Indeed we can write &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hasEdge&lt;/code&gt; using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;paragraph&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;hasEdge&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Eq&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Bool&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;hasEdge&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Edge&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;paragraph&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Miss&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Tail&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Miss&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;of&lt;/span&gt;
      &lt;span class=&quot;kt&quot;&gt;Miss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;
      &lt;span class=&quot;kt&quot;&gt;Tail&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Tail&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;
      &lt;span class=&quot;kt&quot;&gt;Edge&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Edge&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;yy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;of&lt;/span&gt;
      &lt;span class=&quot;kt&quot;&gt;Miss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;
      &lt;span class=&quot;kt&quot;&gt;Tail&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hasVertex&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;yy&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Edge&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Tail&lt;/span&gt;
      &lt;span class=&quot;kt&quot;&gt;Edge&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Edge&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;the-goal&quot;&gt;The goal&lt;/h3&gt;

&lt;p&gt;Our current goal is to optimize&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;paragraph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bind&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;to something that traverses the original graph &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x&lt;/code&gt; only once. If we achieve this, it will solve our problem with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hasEdge&lt;/code&gt; &lt;em&gt;and&lt;/em&gt; for every function expressed with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;paragraph&lt;/code&gt;.&lt;/p&gt;

&lt;h4 id=&quot;is-this-even-possible&quot;&gt;Is this even possible?&lt;/h4&gt;

&lt;p&gt;A legitimate question is: can we indeed do such a thing? Is not &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;paragraph&lt;/code&gt; too general to allow fusion?&lt;/p&gt;

&lt;p&gt;This is not so simple and I did not found an optimization that works for every paramorphism (and I don’t think it is possible), but only for a subclass of them.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/nobrakal/coq-alga/blob/a8d45e3b96d39b8cf79f259540ec29204ede7e5c/src/Paramorphism.v#L28&quot;&gt;I proved in Coq&lt;/a&gt; the following theorem (that is valid for &lt;em&gt;every&lt;/em&gt; paramorphism):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-coq&quot; data-lang=&quot;coq&quot;&gt;&lt;span class=&quot;k&quot;&gt;Definition&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;apply2L&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;D&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;D&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;D&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;D&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;fun&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Theorem&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;para_compo&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Graph&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Graph&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Graph&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Graph&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Graph&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;paragraph&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;∘&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;paragraph&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;paragraph&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;∘&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;apply2L&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;apply2L&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)).&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;∘&lt;/code&gt; stands for functional composition in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Coq&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;With the right part of the equality, you will traverse the graph once using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;paragraph&lt;/code&gt; until you find a vertex, and then you will apply your “binded” function and traverse the result with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;paragraph&lt;/code&gt; again.&lt;/p&gt;

&lt;p&gt;The only “little” problem is with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apply2L&lt;/code&gt;. Indeed, you need to change the last arguments of your paramorphism to reflect the bind in the unconsumed part of the graph.&lt;/p&gt;

&lt;p&gt;You can view this by a &lt;em&gt;duplication&lt;/em&gt; of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bind&lt;/code&gt; operation: it gets incorporated in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;paragraph&lt;/code&gt; expression &lt;em&gt;but also&lt;/em&gt; for the two lasts arguments of the combination function. This leads to a simple problem: you don’t want to rewrite functions that use both the unconsumed graph &lt;em&gt;and&lt;/em&gt; the recursive call. If you allow this, the rewriting will lead to a double computation of the “binded” function (one for the recursive call, and one for the delayed &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bind&lt;/code&gt; on the unconsumed arguments).&lt;/p&gt;

&lt;p&gt;We need to ensure that we rewrite only functions that make the promise to use either the recursive call or the unconsumed graph. Note that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hasEdge&lt;/code&gt; fulfill this promise, so all is well!&lt;/p&gt;

&lt;h2 id=&quot;implementation&quot;&gt;Implementation&lt;/h2&gt;

&lt;h3 id=&quot;promises-need-to-be-kept&quot;&gt;Promises need to be kept&lt;/h3&gt;

&lt;p&gt;I don’t like “functions that make promises”, so we need to encode the promise “I either use the recursive call or the unconsumed graph” in types.&lt;/p&gt;

&lt;h4 id=&quot;the-not-working-but-elegant-version&quot;&gt;The not working but elegant version&lt;/h4&gt;

&lt;p&gt;Ideally, this kind of function can be encoded with:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;kr&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Combination&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;Either&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Either&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Either&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;First of all, this indeed encode the promise, almost literally: your function either use the left recursive call or the left unconsumed part and then produce a function that either use the right recursive call or the unconsumed right graph.&lt;/p&gt;

&lt;p&gt;But with this definition comes a problem: the second argument of the combination function is “hidden” in another function. For example, with such a definition, the only way to define &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apply2L&lt;/code&gt; is something like:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;apply2L&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Combination&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Combination&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;apply2L&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Left&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Left&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;of&lt;/span&gt;
   &lt;span class=&quot;kt&quot;&gt;Left&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&apos;&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Left&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&apos;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;
   &lt;span class=&quot;kt&quot;&gt;Right&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Right&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&apos;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;apply2L&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Right&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Right&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;of&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;Left&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&apos;&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Left&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&apos;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;Right&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Right&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&apos;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Your only choice (and this is logical) is to apply first the function (either on the recursive call of the unconsumed graph) and discuss its result. Sadly, this way will lead to a problem: one cannot fuse any operation (like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bind&lt;/code&gt;) on the unconsumed right part of the graph. GHC is “blinded” by the function encoding and cannot inline what the returned function (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f&apos;&lt;/code&gt;) really is (since it depends &lt;em&gt;at run-time&lt;/em&gt; on the result of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;A solution to this problem is to write explicitly the combination function, giving the user only the control on some parameter.&lt;/p&gt;

&lt;h4 id=&quot;a-working-solution&quot;&gt;A working solution&lt;/h4&gt;
&lt;p&gt;Here is a solution, not very classy, but working (if you find something better, don’t hesitate to tell me) :&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;kr&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Combination&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;B&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;L&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Bool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;R&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Bool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;You have three possibilities:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;B&lt;/code&gt;: it is a classic combination function (like the one we can find in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldg&lt;/code&gt;).&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;L&lt;/code&gt;: you inspect the left recursive call using a predicate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;b -&amp;gt; Bool&lt;/code&gt;, decide what to do, either call the recursion on the right part or inspect the right unconsumed part.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;R&lt;/code&gt;: the same, but you inspect first the right recursive call.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;switchCombi&lt;/code&gt; that effectively transform this data into a combination function for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;paragraph&lt;/code&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;switchCombi&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Combination&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;switchCombi&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;B&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;switchCombi&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;L&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pred&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pred&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c1&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c2&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;switchCombi&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;R&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pred&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pred&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c1&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c2&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Note that providing a constructor for the case &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Graph a -&amp;gt; Graph a -&amp;gt; b&lt;/code&gt; is not very interesting, since it does not use any recursive calls.&lt;/p&gt;

&lt;p&gt;Thus we can define &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;paragraphR&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;paragraphR&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Combination&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Combination&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;paragraphR&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;paragraph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;switchCombi&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;switchCombi&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{-# INLINE [0] paragraphR #-}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Then it is easy to define &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hasEdge&lt;/code&gt; using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;paragraphR&lt;/code&gt; :&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;hasEdge&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Eq&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Bool&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;hasEdge&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Edge&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;paragraphR&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Miss&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;B&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;R&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Tail&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Miss&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;of&lt;/span&gt;
      &lt;span class=&quot;kt&quot;&gt;Miss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;
      &lt;span class=&quot;kt&quot;&gt;Tail&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Tail&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;
      &lt;span class=&quot;kt&quot;&gt;Edge&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Edge&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;cp&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Tail&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;c1&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
      &lt;span class=&quot;kr&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;of&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;Miss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;
        &lt;span class=&quot;kr&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;c2&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hasVertex&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Edge&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Tail&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;foldg-adaptation&quot;&gt;Foldg adaptation&lt;/h3&gt;

&lt;p&gt;To adapt this for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;paragraphR&lt;/code&gt; we need to change the previous encoding of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Foldg&lt;/code&gt; with&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;kt&quot;&gt;Paragraph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;forall&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Combination&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Combination&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;That is a structure that represents exactly the type of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;paragraphR&lt;/code&gt; (like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Foldg&lt;/code&gt; represented &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldg&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Given a function into its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Paragraph&lt;/code&gt; form, it is easy to get the graph it represents:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;buildR&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Paragraph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;buildR&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Empty&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Vertex&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;B&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Overlay&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;B&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Connect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{-# INLINE [1] buildR #-}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;bind-arguments&quot;&gt;Bind arguments&lt;/h3&gt;

&lt;p&gt;Some problems come with the choices we made, lets see directly the rules and some auxilliary functions (don’t run away!):&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;apply2LR&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Combination&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Combination&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;apply2LR&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;B&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;B&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;apply2LR&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;L&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;L&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;apply2LR&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;R&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;R&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;-- Bind already in its &quot;buildR&quot; form (to avoid a rewriting cycle with &quot;buildR/bindR&quot;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;buildBindR&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;buildBindR&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;buildR&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;
	  &lt;span class=&quot;n&quot;&gt;paragraphR&lt;/span&gt;
	    &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;
	    &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;paragraphR&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;apply2LR&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bind2R&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;apply2LR&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bind2R&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	    &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;-- bind without rewrite rules (to avoid a rewriting cycle with &quot;buildR/bindR&quot;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;bind2R&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foldg&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Empty&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Overlay&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Connect&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{-# INLINE buildBindR #-}&lt;/span&gt;

&lt;span class=&quot;cp&quot;&gt;{-# RULES
&quot;buildR/bindR&quot; forall (f::a -&amp;gt; Graph b) g.
  bindR g f =
    buildR
      (\e v o c -&amp;gt;
	    paragraphR
	      e
	      ((paragraphR e v o c) . f)
	      (apply2LR buildBindR o)
	      (apply2LR buildBindR c)
	      g
      )

&quot;foldg/buildR&quot; forall e v o c (g :: Paragraph a).
  foldg e v o c (buildR g) = g e v (B o) (B c)

&quot;paragraphR/buildR&quot; forall e v o c (g :: Paragraph a).
  paragraphR e v o c (buildR g) = g e v o c
 #-}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Far more scary than the previous ones, isn’t it?&lt;/p&gt;

&lt;p&gt;Let me explain what are doing the rules:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;buildR/bindR&quot;&lt;/code&gt; is converting a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bind&lt;/code&gt; into its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;buildR&lt;/code&gt; equivalent (it is, up to some names, exactly the previous theorem).&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;foldg/buildR&quot;&lt;/code&gt; assure the compatibility with the previous work: you can always fuse a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldg&lt;/code&gt; on the left of a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bind&lt;/code&gt;!&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;paragraphR/buildR&quot;&lt;/code&gt; is the main rule and fuse a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;paragraphR&lt;/code&gt; on the left of a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bind&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The complication comes from the fact that we fuse with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bind&lt;/code&gt;. Because we allow the combination function of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;paragraph&lt;/code&gt; to reason on the graph itself, we will have to remember the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bind&lt;/code&gt; operation that needs to be made on the “not already consumed argument” of our paramorphism (more explicitly, we are &lt;em&gt;delaying&lt;/em&gt; the bind operation).
This is done by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apply2LR&lt;/code&gt; which apply &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bind&lt;/code&gt; to the two lasts arguments.&lt;/p&gt;

&lt;p&gt;Even with this, the above rules seem a lot more complicated than necessary.&lt;/p&gt;

&lt;h4 id=&quot;warning-cycle&quot;&gt;Warning: cycle&lt;/h4&gt;

&lt;p&gt;One (who does not read commentaries) might ask&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Why do you use buildBindR and not directly bind?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Because there is a little problem. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;buildR/bindR&quot;&lt;/code&gt; rules is precisely rewriting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bind&lt;/code&gt; occurrences, so using it directly in the right part of the equality will lead to a rewriting cycle.&lt;/p&gt;

&lt;p&gt;BUT&lt;/p&gt;

&lt;p&gt;We need this &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bind&lt;/code&gt; and we need it in a “re-writable form”. If you look at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hasEdge&lt;/code&gt;, you see that it uses &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hasVertex&lt;/code&gt; on the unconsumed part of the graph, and this function can be fused with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bind&lt;/code&gt;. So, ideally, standard shortcut deforestation will also happen here, directly on the argument of combination function for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Connect&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The only possibility is to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;buildBindR&lt;/code&gt;, which is only &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bind&lt;/code&gt; is its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;buildR&lt;/code&gt; form. We use the direct code of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bind&lt;/code&gt; for the arguments, because we do not want to come into a rewriting cycle.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;h3 id=&quot;is-all-of-this-working&quot;&gt;Is all of this working?&lt;/h3&gt;

&lt;p&gt;Yes! Using &lt;a href=&quot;http://hackage.haskell.org/package/inspection-testing&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inspection-testing&lt;/code&gt;&lt;/a&gt; (a great tool that compare the code produced by GHC at compile-time), the following code compiles:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;hasEdgeF&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Eq&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Bool&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;hasEdgeF&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hasEdge&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fmap&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;hasEdgeFR&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Eq&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Bool&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;hasEdgeFR&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Edge&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Empty&lt;/span&gt;         &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Miss&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Vertex&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Tail&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Miss&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Overlay&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
      &lt;span class=&quot;kr&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;of&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;Miss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;Tail&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Tail&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;Edge&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Edge&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Connect&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
      &lt;span class=&quot;kr&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;in&lt;/span&gt;
        &lt;span class=&quot;kr&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Tail&lt;/span&gt;
        &lt;span class=&quot;kr&quot;&gt;then&lt;/span&gt;
          &lt;span class=&quot;kr&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gx&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;of&lt;/span&gt;
            &lt;span class=&quot;kt&quot;&gt;Miss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;
            &lt;span class=&quot;kr&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gx&lt;/span&gt;
        &lt;span class=&quot;kr&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foldg&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;False&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;||&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;||&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Edge&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Tail&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;-- If this compiles, it means that hasEdge and hasEdgeFR have (almost) the same&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;inspect&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;&apos;hasEdgeF&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;&apos;hasEdgeFR&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;What happened?&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fmap&lt;/code&gt; was &lt;em&gt;entirely&lt;/em&gt; fused with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hasEdge&lt;/code&gt;. By entirely, I mean not only the test on vertices, but also the composition of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hasVertex&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fmap&lt;/code&gt; happened!&lt;/p&gt;

&lt;p&gt;More precisely, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fmap&lt;/code&gt; operation is made &lt;em&gt;only&lt;/em&gt; on the needed part of the graph. That is, if your graph is like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Overlay a b&lt;/code&gt; where the desired edge is on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a&lt;/code&gt; part, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;b&lt;/code&gt; part of the graph &lt;em&gt;will not&lt;/em&gt; be evaluated (and particularly not the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fmap&lt;/code&gt; operation on this part).&lt;/p&gt;

&lt;h3 id=&quot;what-remains-to-be-done&quot;&gt;What remains to be done&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Add list optimizations: a classic way to create an algebraic graph is to use a list (an adjacency list for example). For example &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;edges :: [(a,a)] -&amp;gt; Graph a&lt;/code&gt; that make an algebraic graph from a list of edges.
We already have some rewrite rules to optimize expressions like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldg e v o c (edges xs)&lt;/code&gt; (because we know how the graph is made, we can avoid building an intermediate graph). Is this possible with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;paragraph&lt;/code&gt;?&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Alga: all I described here is already implemented on my fork of Alga, but there is certainly some cleanup and verifications to make it available in the official Alga repository!&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Proofs: I only proved that we &lt;em&gt;can&lt;/em&gt; optimize things. It will be nice to actually prove that the rewriting process is correct (that is: we rewrite things only to equivalent ones).&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;thanks&quot;&gt;Thanks&lt;/h3&gt;

&lt;p&gt;Thanks to Andrey Mokhov for his review of this article.&lt;/p&gt;</content><author><name></name></author><category term="Haskell" /><summary type="html">Introduction</summary></entry><entry><title type="html">Some results about algebraic graphs homomorphisms</title><link href="https://blog.nyarlathotep.one/2018/12/algebraic-graphs-homomorphisms/" rel="alternate" type="text/html" title="Some results about algebraic graphs homomorphisms" /><published>2018-12-09T00:00:00+01:00</published><updated>2018-12-09T00:00:00+01:00</updated><id>https://blog.nyarlathotep.one/2018/12/algebraic-graphs-homomorphisms</id><content type="html" xml:base="https://blog.nyarlathotep.one/2018/12/algebraic-graphs-homomorphisms/">&lt;h2 id=&quot;prelude&quot;&gt;Prelude&lt;/h2&gt;

&lt;p&gt;In my previous post &lt;a href=&quot;https://blog.nyarlathotep.one/2018/09/rewrite-rules-and-a-specific-fold/&quot;&gt;“Rewrite rules and a specific fold: use optimization techniques from GHC.Base”&lt;/a&gt;, I described a technique to optimize composition of a custom fold and some functions on algebraic graphs, implemented in Haskell in the &lt;a href=&quot;https://github.com/snowleopard/alga&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;alga&lt;/code&gt;&lt;/a&gt; library.&lt;/p&gt;

&lt;p&gt;The goal of this post is to try to specify exactly what are the classes of functions we can optimize. I will try to do this in a “mathematical” way (don’t run, this is actually fun), with all my results proved in &lt;a href=&quot;https://coq.inria.fr/&quot;&gt;Coq&lt;/a&gt;, a very cool proof assistant (it is a first time for me, please be indulgent with my code :) ).&lt;/p&gt;

&lt;p&gt;All the work can be found at &lt;a href=&quot;https://github.com/nobrakal/coq-alga/&quot;&gt;https://github.com/nobrakal/coq-alga/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The version of this repositiory when I wrote this article can be found at &lt;a href=&quot;https://github.com/nobrakal/coq-alga/tree/4586bda0847b059b263cc4a1c8685004c9461d6c&quot;&gt;https://github.com/nobrakal/coq-alga/tree/4586bda0847b059b263cc4a1c8685004c9461d6c&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;alga-theory&quot;&gt;Alga theory&lt;/h2&gt;

&lt;p&gt;I had to implement some of the already known algebraic graphs theory in Coq (already know because proved in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;agda&lt;/code&gt; on a &lt;a href=&quot;https://github.com/algebraic-graphs/agda/&quot;&gt;dedicated repository&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;All of this work is in the &lt;a href=&quot;https://github.com/nobrakal/coq-alga/blob/4586bda0847b059b263cc4a1c8685004c9461d6c/src/Graph.v&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/Graph.v&lt;/code&gt;&lt;/a&gt; file:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The data structure, an inductive one called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Graph&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Some standards functions (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldg&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;isEmpty&lt;/code&gt;…).&lt;/li&gt;
  &lt;li&gt;Useful lemmas on them.&lt;/li&gt;
  &lt;li&gt;Axioms on the graph equality (in a Coq class called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EqG&lt;/code&gt;).&lt;/li&gt;
  &lt;li&gt;Indications for Coq to allow rewriting (using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rewrite&lt;/code&gt; tactic) when working with equal graphs.&lt;/li&gt;
  &lt;li&gt;Some proofs about the graph equality (especially, that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Empty&lt;/code&gt; is the identity for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Overlay&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;a-note-on-equality&quot;&gt;A note on equality&lt;/h3&gt;
&lt;p&gt;Here the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;=&lt;/code&gt; symbol is ambiguous.&lt;/p&gt;

&lt;p&gt;So we will distinguish:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a = b&lt;/code&gt; for the structural equality (a.k.a. Leibniz equality) between &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;b&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;R a b&lt;/code&gt; for graph equality relation between &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;b&lt;/code&gt; (note that the axioms of this relation are satisfied by others relations than graph equality, so things are not so simple).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;homomorphism&quot;&gt;Homomorphism&lt;/h2&gt;

&lt;p&gt;The work described here can be found in the &lt;a href=&quot;https://github.com/nobrakal/coq-alga/blob/4586bda0847b059b263cc4a1c8685004c9461d6c/src/Homomorphism.v&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/Homomorphism.v&lt;/code&gt;&lt;/a&gt; file.&lt;/p&gt;

&lt;h3 id=&quot;graph-homomorphism&quot;&gt;Graph homomorphism&lt;/h3&gt;

&lt;p&gt;An &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;homomorphism&lt;/code&gt; in algebra theory is (quoting &lt;a href=&quot;https://en.wikipedia.org/wiki/Homomorphism&quot;&gt;Wikipedia&lt;/a&gt;) “a structure-preserving map between two algebraic structures of the same type”.&lt;/p&gt;

&lt;p&gt;For us, a correct homomorphism &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f :: Graph a -&amp;gt; Graph b&lt;/code&gt; should satisfy:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f Empty = Empty&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f (Overlay a b) = Overlay (f a) (f b)&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f (Connect a b) = Connect (f a) (f b)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is encoded in a Coq class called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Homomorphism&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Coq&quot;&gt;Class Homomorphism {A B:Type} (f : Graph A -&amp;gt; Graph B) : Prop := {
  Hom_Empty :&amp;gt; f Empty = Empty;
  Hom_Overlay :&amp;gt; forall a b, f (Overlay a b) = Overlay (f a) (f b) ;
  Hom_Connect :&amp;gt; forall a b, f (Connect a b) = Connect (f a) (f b)
 }.
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;equivalence-with-bind-functions&quot;&gt;Equivalence with bind-functions&lt;/h3&gt;

&lt;p&gt;Let us recall briefly the concerned Haskell functions:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-Haskell&quot;&gt;data Graph a = Empty
             | Vertex a
             | Overlay (Graph a) (Graph a)
             | Connect (Graph a) (Graph a)

foldg :: b -&amp;gt; (a -&amp;gt; b) -&amp;gt; (b -&amp;gt; b -&amp;gt; b) -&amp;gt; (b -&amp;gt; b -&amp;gt; b) -&amp;gt; Graph a -&amp;gt; b
foldg e v o c = go
  where
    go Empty         = e
    go (Vertex  x  ) = v x
    go (Overlay x y) = o (go x) (go y)
    go (Connect x y) = c (go x) (go y)

(&amp;gt;&amp;gt;=) :: Graph a -&amp;gt; (a -&amp;gt; Graph b) -&amp;gt; Graph b
g &amp;gt;&amp;gt;= f = foldg Empty f Overlay Connect g
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A cool result is that such homomorphisms are exactly bind-functions, that is to say any graph homomorphism can be expressed with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(&amp;gt;&amp;gt;=)&lt;/code&gt; operator.&lt;/p&gt;

&lt;h4 id=&quot;proof&quot;&gt;Proof&lt;/h4&gt;

&lt;p&gt;So any function expressed with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(&amp;gt;&amp;gt;=)&lt;/code&gt; is clearly a graph homomorphism (this is proved in the &lt;a href=&quot;https://github.com/nobrakal/coq-alga/blob/4586bda0847b059b263cc4a1c8685004c9461d6c/src/Homomorphism.v#L17&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bind_is_hom&lt;/code&gt; lemma&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;A fun fact is that the reciprocal is also true, like shown in the &lt;a href=&quot;https://github.com/nobrakal/coq-alga/blob/4586bda0847b059b263cc4a1c8685004c9461d6c/src/Homomorphism.v#L23&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hom_is_bind&lt;/code&gt; lemma&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Coq&quot;&gt;Lemma hom_is_bind A B (hom: Graph A -&amp;gt; Graph B):
  Homomorphism hom -&amp;gt; hom = bind (hom ∘ Vertex).
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That is, an homomorphism is equal to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bind&lt;/code&gt; with its definition for a vertex. A graph homomorphism is indeed entirely defined by what it is doing on a leaf of the graph expression.&lt;/p&gt;

&lt;h4 id=&quot;examples&quot;&gt;Examples&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fmap f&lt;/code&gt; is a graph homomorphism, using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Vertex . f&lt;/code&gt; as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bind&lt;/code&gt; argument.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;removeVertex v&lt;/code&gt; is a graph homomorphism, using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\x -&amp;gt; if v == x then Vertex x else Empty&lt;/code&gt; as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bind&lt;/code&gt; argument.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;theorem-1-composition-of-a-graph-homomorphism-and-a-foldg-function&quot;&gt;Theorem 1: Composition of a graph homomorphism and a foldg function&lt;/h3&gt;
&lt;p&gt;Any graph homomorphism can be fused with a foldg-function, like show in the &lt;a href=&quot;https://github.com/nobrakal/coq-alga/blob/4586bda0847b059b263cc4a1c8685004c9461d6c/src/Homomorphism.v#L56&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldg_bind&lt;/code&gt; theorem&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-Coq&quot;&gt;Theorem foldg_bind A B C (e : C) (v: B -&amp;gt; C)
  (o:C -&amp;gt; C -&amp;gt; C) (c:C -&amp;gt; C -&amp;gt; C) (f_v : A -&amp;gt; Graph B):
    foldg e v o c ∘ bind f_v = foldg e (foldg e v o c ∘ f_v) o c.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Basically, because a graph homomorphism preserve the structure, it can easily be fused with something that destruct this structure: this is shortcut deforestation.&lt;/p&gt;

&lt;h3 id=&quot;theorem-2-composition-of-graph-homomorphisms&quot;&gt;Theorem 2: Composition of graph homomorphisms&lt;/h3&gt;

&lt;p&gt;A cool corollary of the previous theorem is that the composition of two graph homomorphisms is again a graph homomorphism.&lt;/p&gt;

&lt;h4 id=&quot;proof-1&quot;&gt;Proof&lt;/h4&gt;
&lt;p&gt;This is proved in the &lt;a href=&quot;https://github.com/nobrakal/coq-alga/blob/4586bda0847b059b263cc4a1c8685004c9461d6c/src/Homomorphism.v#L79&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bind_compo&lt;/code&gt; theorem&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-Coq&quot;&gt;Theorem bind_compo A B C (hom1 : Graph A -&amp;gt; Graph B) (hom2 : Graph B -&amp;gt; Graph C):
 (Homomorphism hom1) /\ (Homomorphism hom2) -&amp;gt;
 hom2 ∘ hom1 = bind (hom2 ∘ hom1 ∘ Vertex).
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;problems&quot;&gt;Problems&lt;/h3&gt;

&lt;p&gt;So graph homomorphisms are cool, but not always what we want:
in the examples of graph homomorphisms, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;removeVertex&lt;/code&gt; is leaving empty leaves in the structure. If it was removing them (like the actual &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;removeVertex&lt;/code&gt; in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;alga&lt;/code&gt; library), it will change the graph structure, and thus will not be a graph homomorphism as we defined it.
Such functions are very useful, so we must lower our restrictions and only require preservation of the graph equality to include them.&lt;/p&gt;

&lt;h2 id=&quot;reduced-graph-homomorphism&quot;&gt;Reduced graph homomorphism&lt;/h2&gt;

&lt;p&gt;Theorems of this section are in the &lt;a href=&quot;https://github.com/nobrakal/coq-alga/blob/4586bda0847b059b263cc4a1c8685004c9461d6c/src/ReducedHomo.v&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/ReducedHomo.v&lt;/code&gt;&lt;/a&gt; file.&lt;/p&gt;

&lt;h3 id=&quot;definition&quot;&gt;Definition&lt;/h3&gt;
&lt;p&gt;A function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f :: Graph a -&amp;gt; Graph b&lt;/code&gt; is called a &lt;strong&gt;reduced graph homomorphism&lt;/strong&gt; if:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-Haskell&quot;&gt;R (f Empty) Empty
R (f (Overlay a b)) (Overlay (f a) (f b))
R (f (Connect a b)) (Connect (f a) (f b))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So we require only that the function has the same properties than a graph homomorphism, but with graph equality instead of the structural one.&lt;/p&gt;

&lt;p&gt;This idea is encapsulated in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Reduced_hom&lt;/code&gt; Coq class:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Coq&quot;&gt;Class Reduced_hom {A B : Type} (R: relation (Graph B)) (f : Graph A -&amp;gt; Graph B) : Prop :=
{
  RHom_EqG :&amp;gt; EqG B R;
  RHom_Empty :&amp;gt;  R (f Empty) Empty ;
  RHom_Overlay :&amp;gt; forall a b, R (f (Overlay a b)) (Overlay (f a) (f b)) ;
  RHom_Connect :&amp;gt; forall a b, R (f (Connect a b)) (Connect (f a) (f b))
}.
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;theorem-3-reduced-graph-homomorphism-are-indeed-reduced-graph-homomorphism&quot;&gt;Theorem 3: Reduced graph homomorphism are indeed reduced graph homomorphism&lt;/h3&gt;
&lt;p&gt;Graph homomorphism are reduced graph homomorphism.&lt;/p&gt;

&lt;p&gt;The reverse is false.&lt;/p&gt;

&lt;h4 id=&quot;proof-2&quot;&gt;Proof&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;“graph homomorphism are reduced graph homomorphism.”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is proved in the &lt;a href=&quot;https://github.com/nobrakal/coq-alga/blob/4586bda0847b059b263cc4a1c8685004c9461d6c/src/ReducedHomo.v#L19&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hom_is_reduced_hom&lt;/code&gt; theorem&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The idea is only to use the fact that, for all &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a b :: Graph A&lt;/code&gt;, if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a = b&lt;/code&gt; then &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;R a b&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;“The reverse is false”.
Using
    &lt;pre&gt;&lt;code class=&quot;language-Haskell&quot;&gt;wforget :: Graph a -&amp;gt; Graph b
wforget _ = Empty
&lt;/code&gt;&lt;/pre&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wforget&lt;/code&gt; is clearly a reduced homomorphism (this is proved in the &lt;a href=&quot;https://github.com/nobrakal/coq-alga/blob/4586bda0847b059b263cc4a1c8685004c9461d6c/src/ReducedHomo.v#L53&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;const_empty_is_reduced_hom&lt;/code&gt; theorem&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;But it is also clearly not a graph homorphism, this is proved by the absurd in the &lt;a href=&quot;https://github.com/nobrakal/coq-alga/blob/4586bda0847b059b263cc4a1c8685004c9461d6c/src/ReducedHomo.v#L78&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;const_empty_is_not_hom&lt;/code&gt; theorem&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;the-case-of-empty-leaves-a-class-of-reduced-graph-homomorphism&quot;&gt;The case of empty leaves: a class of reduced graph homomorphism&lt;/h2&gt;

&lt;p&gt;Theorems of this section are in the &lt;a href=&quot;https://github.com/nobrakal/coq-alga/blob/4586bda0847b059b263cc4a1c8685004c9461d6c/src/SmartHomo.v&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/SmartHomo.v&lt;/code&gt;&lt;/a&gt; file.&lt;/p&gt;

&lt;h4 id=&quot;prelude-1&quot;&gt;Prelude&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-Haskell&quot;&gt;-- Remove empty leaves around a graph operator (usually Overlay or Connect)
kSimpl :: (Graph a -&amp;gt; Graph a -&amp;gt; Graph a) -&amp;gt; Graph a -&amp;gt; Graph a -&amp;gt; Graph a
kSimpl c x y =
  if isEmpty x
  then if isEmpty y
    then Empty
    else y
  else if isEmpty y
    then x
    else c x y

-- Remove empty leaves of a graph
dropEmpty :: Graph a -&amp;gt; Graph a
dropEmpty = foldg Empty Vertex (kSimpl Overlay) (kSimpl Connect)
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;definition-1&quot;&gt;Definition&lt;/h3&gt;

&lt;p&gt;A function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f :: Graph a -&amp;gt; Graph b&lt;/code&gt; is called a &lt;strong&gt;smart graph homomorphism&lt;/strong&gt; if it can be described using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f_w :: a -&amp;gt; Graph b&lt;/code&gt; such that&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-Haskell&quot;&gt;f g = dropEmpty (g &amp;gt;&amp;gt;= f_w)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Obviously, such a function can go through the graph only once, using&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Haskell&quot;&gt;f = foldg Empty f_w (kSimpl Overlay) (kSimpl Connect)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is proved in the &lt;a href=&quot;https://github.com/nobrakal/coq-alga/blob/4586bda0847b059b263cc4a1c8685004c9461d6c/src/SmartHomo.v#L56&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smart_hom_single&lt;/code&gt; theorem&lt;/a&gt;.&lt;/p&gt;

&lt;h4 id=&quot;example&quot;&gt;Example&lt;/h4&gt;
&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;induce&lt;/code&gt; is a smart graph homomorphism (maybe the definition was made for it…):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-Haskell&quot;&gt;induce :: (p -&amp;gt; Bool) -&amp;gt; Graph a -&amp;gt; Graph a
induce p =
  foldg
    Empty
    (\x -&amp;gt; if p x then Vertex x else Empty)
    (kSimpl Overlay)
    (kSimpl Connect)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is proved in the &lt;a href=&quot;https://github.com/nobrakal/coq-alga/blob/4586bda0847b059b263cc4a1c8685004c9461d6c/src/SmartHomo.v#L84&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;induce_smart_hom&lt;/code&gt; theorem&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;theorem-4-smart-graph-homomorphisms-are-reduced-homomorphisms&quot;&gt;Theorem 4: smart graph homomorphisms are reduced homomorphisms.&lt;/h3&gt;

&lt;p&gt;This seems clear because empty leaves does not play any role in graph equality, but it takes me anyway 44 lines to prove it.&lt;/p&gt;

&lt;p&gt;It is proved in the &lt;a href=&quot;https://github.com/nobrakal/coq-alga/blob/4586bda0847b059b263cc4a1c8685004c9461d6c/src/SmartHomo.v#L165&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;smart_hom_is_reduced_hom&lt;/code&gt; theorem&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-Coq&quot;&gt;Theorem smart_hom_is_reduced_hom A B (R: relation (Graph B))
  (f : Graph A -&amp;gt; Graph B) :
    EqG B R -&amp;gt; Smart_hom f -&amp;gt; Reduced_hom R f.
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;theorem-5-composition-of-smart-graph-homomorphisms&quot;&gt;Theorem 5: Composition of smart graph homomorphisms&lt;/h3&gt;
&lt;p&gt;The composition of two smart graph homomorphisms is again a smart graph homomorphism.&lt;/p&gt;

&lt;h4 id=&quot;proof-3&quot;&gt;Proof&lt;/h4&gt;

&lt;p&gt;This was hard to prove because not clear at first glance (well mostly, it was long, using 280 lines ^^). The idea is to see that the composition of two smart graph homomorphisms is something not so strange:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Coq&quot;&gt;Theorem smart_hom_compo A B C (s1 : Graph A -&amp;gt; Graph B)
  (s2 : Graph B -&amp;gt; Graph C): (Smart_hom s1) /\ (Smart_hom s2) -&amp;gt;
  s2 ∘ s1 = foldg Empty (s2 ∘ s1 ∘ Vertex) (kSimpl Overlay) (kSimpl Connect).
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(The proof is &lt;a href=&quot;https://github.com/nobrakal/coq-alga/blob/4586bda0847b059b263cc4a1c8685004c9461d6c/src/SmartHomo.v#L325&quot;&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Then see that this form allow us to prove that the composition is again a smart graph morphism:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Coq&quot;&gt;Theorem smart_hom_compo_is_smart A B C (s1 : Graph A -&amp;gt; Graph B)
  (s2 : Graph B -&amp;gt; Graph C):
    (Smart_hom s1) /\ (Smart_hom s2) -&amp;gt; Smart_hom (s2 ∘ s1).
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(The proof is &lt;a href=&quot;https://github.com/nobrakal/coq-alga/blob/4586bda0847b059b263cc4a1c8685004c9461d6c/src/SmartHomo.v#L463&quot;&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;So all this work to prove that we can optimize anything like:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-Haskell&quot;&gt;foldg e v o c . morph1 . morph2 . [...] . morphn
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;to a function that will only go through the graph once.&lt;/p&gt;

&lt;p&gt;if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;morph1&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;morph2&lt;/code&gt;, …, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;morphn&lt;/code&gt; are graph homomorphisms (theorem 1 and theorem 2).&lt;/p&gt;

&lt;p&gt;We can also optimize any combination of smart graph homomorphisms (theorem 5).&lt;/p&gt;

&lt;h3 id=&quot;what-is-left&quot;&gt;What is left&lt;/h3&gt;

&lt;p&gt;There is certainly some things to do playing with these results:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Find a cool (and efficient) implementation for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;alga&lt;/code&gt; library.&lt;/li&gt;
  &lt;li&gt;The composition of smart graph homomorphisms is preserving graph structure, maybe there is an efficient one that is only preserving graph equality ?&lt;/li&gt;
  &lt;li&gt;Determine precisely the class of reduced homomorphisms. That is to say, is there an equivalence with a well known class of functions like for graph homomorphisms ?&lt;/li&gt;
  &lt;li&gt;What is the class of reduced homomorphisms that we can compose ?&lt;/li&gt;
  &lt;li&gt;Can this be generalised to arbitrary algebraic data types that have some notion of an Empty constructor?&lt;/li&gt;
  &lt;li&gt;And certainly many other things :)&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;thanks&quot;&gt;Thanks&lt;/h4&gt;

&lt;p&gt;Thanks to Andrey Mokhov for his review of this article.&lt;/p&gt;</content><author><name></name></author><category term="Haskell" /><summary type="html">Prelude</summary></entry><entry><title type="html">Rewrite rules and a specific fold: use optimization techniques from GHC.Base</title><link href="https://blog.nyarlathotep.one/2018/09/rewrite-rules-and-a-specific-fold/" rel="alternate" type="text/html" title="Rewrite rules and a specific fold: use optimization techniques from GHC.Base" /><published>2018-09-30T00:00:00+02:00</published><updated>2018-09-30T00:00:00+02:00</updated><id>https://blog.nyarlathotep.one/2018/09/rewrite-rules-and-a-specific-fold</id><content type="html" xml:base="https://blog.nyarlathotep.one/2018/09/rewrite-rules-and-a-specific-fold/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;The &lt;a href=&quot;http://hackage.haskell.org/package/base-4.11.0.0/docs/src/GHC.Base.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GHC.Base&lt;/code&gt;&lt;/a&gt; module defines, in particular, base functions on lists and several rewrite rules to optimize them (if you are not familiar with rewrite rules, I suggest the reading of my previous article &lt;a href=&quot;https://blog.nyarlathotep.one/2018/07/ghc-one-compiler-to-rule-them-all/&quot;&gt;“GHC, one compiler to RULE them all”&lt;/a&gt;, or directly the &lt;a href=&quot;https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#rewrite-rules&quot;&gt;related GHC documentation&lt;/a&gt;). Especially, these rules allow&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;foldr&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;to be rewritten by the compiler into something similar to&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;foldr&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xs&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;These rules improve the expression by allowing a single reading of the list, whereas the first implementation was reading it twice.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://hackage.haskell.org/package/algebraic-graphs&quot;&gt;Alga&lt;/a&gt;, a functional implementation of graphs, defines a foldable structure with a fold (named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldg&lt;/code&gt;) specialized for the graph data.&lt;/p&gt;

&lt;p&gt;Can we use the same tricks than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GHC.Base&lt;/code&gt; to optimize compositions of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldg&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fmap&lt;/code&gt;? Spoiler: &lt;em&gt;Yes&lt;/em&gt;, and we can do it without any pain!&lt;/p&gt;

&lt;h2 id=&quot;ghcbase-optimization-on-lists&quot;&gt;GHC.Base optimization on lists&lt;/h2&gt;

&lt;h3 id=&quot;the-build-function&quot;&gt;The build function&lt;/h3&gt;
&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build&lt;/code&gt; is a function you can find in &lt;a href=&quot;https://blog.nyarlathotep.one/2018/07/ghc-one-compiler-to-rule-them-all/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GHC.Base&lt;/code&gt; module&lt;/a&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;build&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;forall&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;forall&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;build&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;[]&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{-# INLINE [1] build #-}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;It is mainly used for optimization when working on list.&lt;/p&gt;

&lt;p&gt;For the next part of this article, I suggest you to read this great article by David Luposchainsky (alias quchen): &lt;a href=&quot;https://github.com/quchen/articles/blob/master/build.md&quot;&gt;https://github.com/quchen/articles/blob/master/build.md&lt;/a&gt;, that mainly explains how the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build&lt;/code&gt; function works, but not fully how it is used.&lt;/p&gt;

&lt;p&gt;I will assume now that you are familiar with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build&lt;/code&gt; and with lambda-lists.&lt;/p&gt;

&lt;h3 id=&quot;fb-functions&quot;&gt;FB functions&lt;/h3&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FB&lt;/code&gt; functions can be seen when searching for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GHC.Base&lt;/code&gt;. For example, with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;map&lt;/code&gt; there is a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mapFB&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;mapFB&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;elt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lst&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lst&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;elt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lst&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lst&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;mapFB&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ys&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ys&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{-# INLINE [0] mapFB #-}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Given a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;c(ons)&lt;/code&gt; function and something to convert a generic type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a&lt;/code&gt; to an element of the list of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;elt&lt;/code&gt; (namely &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f&lt;/code&gt;), you can append an element of a generic type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a&lt;/code&gt; to a lambda-list of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;elt&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;kr&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;myLambdaList&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cons&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cons&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cons&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cons&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
 &lt;span class=&quot;kr&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cons&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mapFB&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cons&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;read&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;0&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;myLambdaList&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cons&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;[]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;will produce&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;But what is the purpose of these functions since a clever reader will have seen that they are not exported? Optimization! Take a look at the type of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mapFB&lt;/code&gt; if we apply to it the two first arguments: now you have a convenient function to use in a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldr&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And why bother to give it a name? Because it will allow us to remember what we were rewriting, and rewrite back function when we were not able to make any optimization.&lt;/p&gt;

&lt;h3 id=&quot;the-rules&quot;&gt;The rules&lt;/h3&gt;

&lt;p&gt;Let us jump quick in the interesting part. Here is (a part of) the rewrite rules used in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GHC.Base&lt;/code&gt; to optimize the code of functions working on lists:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;cp&quot;&gt;{-# RULES
&quot;map&quot;     [~1] forall f xs. map f xs = build (\c n -&amp;gt; foldr (mapFB c f) n xs)

&quot;fold/build&quot;   forall k z (g::forall b. (a-&amp;gt;b-&amp;gt;b) -&amp;gt; b -&amp;gt; b) .
               foldr k z (build g) = g k z

&quot;mapFB&quot;        forall c f g. mapFB (mapFB c f) g = mapFB c (f.g)

&quot;mapList&quot; [1]  forall f. foldr (mapFB (:) f) [] = map f
  #-}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;So what is happening ?&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Only in phase &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2&lt;/code&gt; (the first one), we rewrite every occurrence of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;map&lt;/code&gt; by its strange &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build&lt;/code&gt; equivalent (which use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mapFB&lt;/code&gt;), hoping for fusion to happen.&lt;/li&gt;
  &lt;li&gt;This fusion can happen with two rules, always activated:
    &lt;ul&gt;
      &lt;li&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;fold/build&quot;&lt;/code&gt; one, described in the previously mentioned David’s article, merging a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldr&lt;/code&gt; followed by a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build&lt;/code&gt; (thus allowing the simplification of a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldr f n . map g&lt;/code&gt; expression).&lt;/li&gt;
      &lt;li&gt;If there was two &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mapFB&lt;/code&gt; (and thus something like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;map f . map g&lt;/code&gt; at the beginning of the process), we merge them into a simpler and faster &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;map (f . g)&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;In the meantime, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build&lt;/code&gt; is inlined, allowing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;mapList&quot;&lt;/code&gt; rule to fire.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;If there is any “dumb” &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldr&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mapFB&lt;/code&gt; left, we rewrite them back to a standard form using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;mapList&quot;&lt;/code&gt; rule (only active from the phase &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt; to the end).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For more details, see the &lt;a href=&quot;http://hackage.haskell.org/package/base-4.11.0.0/docs/src/GHC.Base.html#mapFB&quot;&gt;related comment&lt;/a&gt; in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GHC.Base&lt;/code&gt; source.&lt;/p&gt;

&lt;h4 id=&quot;is-it-doing-it-right&quot;&gt;Is it doing it right?&lt;/h4&gt;

&lt;p&gt;Let us take an example.&lt;/p&gt;

&lt;p&gt;Imagine I want to make the sum the elements of a list of integers &lt;em&gt;and&lt;/em&gt; add the whole length of this list. One approach (rather bad) is to add &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt; to each element of the list and then make the sum its elements.
Here is roughly the different phases of the rewriting work made by the compiler if you try to compile such a function:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;foldr&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;          &lt;span class=&quot;n&quot;&gt;foldr&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;build&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foldr&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mapFB&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fold&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foldr&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mapFB&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;               &lt;span class=&quot;n&quot;&gt;foldr&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mapFB&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xs&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inline&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mapFB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foldr&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xs&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Et voila. At the beginning we were reading two times the list and at the end, only one.&lt;/p&gt;

&lt;h2 id=&quot;back-to-graphs&quot;&gt;Back to graphs&lt;/h2&gt;

&lt;h3 id=&quot;the-data&quot;&gt;The data&lt;/h3&gt;

&lt;p&gt;The main data we will work with is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Graph&lt;/code&gt; from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Algebra.Graph&lt;/code&gt; module:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;kr&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Empty&lt;/span&gt;
             &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Vertex&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;
             &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Overlay&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Connect&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We can define a fold specialized for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Graph&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;c1&quot;&gt;-- Generalised &apos;Graph&apos; folding: recursively collapse a &apos;Graph&apos; by applying&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- the provided functions to the leaves and internal nodes of the expression.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- The order of arguments is: empty, vertex, overlay and connect.&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;foldg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;foldg&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Empty&lt;/span&gt;         &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Vertex&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Overlay&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Connect&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{-# INLINE [0] foldg #-}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This useful function allows us to define two key-instances:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;kr&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Functor&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fmap&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foldg&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Empty&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Vertex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Overlay&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Connect&lt;/span&gt;

&lt;span class=&quot;kr&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Foldable&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;foldMap&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foldg&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mempty&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;déjà-vu&quot;&gt;Déjà Vu?&lt;/h3&gt;

&lt;p&gt;Now if we define for convenience:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;mapG&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;mapG&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fmap&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{-# INLINE [0] mapG #-}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We cannot use a rule targetting directly &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fmap&lt;/code&gt; because it does not have any inline pragma attached to its definition and thus can be inlined at any moment. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mapG&lt;/code&gt;’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INLINE&lt;/code&gt; pragma guarantee that we can target &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mapG&lt;/code&gt; in a rewrite rule during the phase &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We are almost in the same position as when working with lists! We have a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldr&lt;/code&gt; and a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;map&lt;/code&gt;.
Can we achieve the same as for lists? Can we optimize&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;foldg&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mapG&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;into&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;foldg&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;using the same method than in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GHC.Base&lt;/code&gt; for lists?&lt;/p&gt;

&lt;h3 id=&quot;introducing-buildg&quot;&gt;Introducing buildG&lt;/h3&gt;

&lt;p&gt;The work is simple, we only need to adapt the type from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GHC.Base&lt;/code&gt; to graphs:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;kr&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;GraphF&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;buildG&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;forall&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;forall&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;GraphF&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;buildG&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Empty&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Vertex&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Overlay&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Connect&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{-# INLINE [1] buildG #-}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;A “lambda-graph” of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a&lt;/code&gt; is a function of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GraphF a b&lt;/code&gt;. So like lambda-lists, applying the four constructors allow us to convert it back to a standard &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Graph&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;add-fb-function&quot;&gt;Add FB function&lt;/h3&gt;

&lt;p&gt;Our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mapGFB&lt;/code&gt; will be slightly different:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;mapGFB&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;mapGFB&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{-# INLINE [0] mapGFB #-}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;It is only a composition of function, but it will allow us to remember that it was made for a rewriting of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mapG&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;the-rules-1&quot;&gt;The rules&lt;/h3&gt;

&lt;p&gt;Now we have all the bricks to build our graph rules:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;cp&quot;&gt;{-# RULES
-- Transform a mapG into its build equivalent
&quot;mapG&quot;   [~1]   forall f g. mapG f g = buildG (\e v o c -&amp;gt; foldg e (mapGFB v f) o c g)

-- Merge a foldg followed by a buildG
&quot;foldg/buildG&quot;  forall e v o c (g::forall b. GraphF a b).
                       foldg e v o c (buildG g) = g e v o c

-- Merge two mapFB
&quot;mapFB/mapFB&quot;   forall c f g. mapGFB (mapGFB c f) g = mapGFB c (f.g)

-- Rules to rewrite un-merged function back
&quot;mapGGraph&quot; [1] forall f. foldg Empty (mapGFB Vertex f) Overlay Connect = mapG f
 #-}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;So, as in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GHC.Base&lt;/code&gt;, we&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Rewrite &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mapG&lt;/code&gt; into its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;buildG&lt;/code&gt; equivalent using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;mapG&quot;&lt;/code&gt; rule&lt;/li&gt;
  &lt;li&gt;Try to optimize what can be optimized with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;foldg/buildG&quot;&lt;/code&gt; and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;mapFB/mapFB&quot;&lt;/code&gt; rules&lt;/li&gt;
  &lt;li&gt;Convert back to standard form what was not optimized using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;mapGGraph&quot;&lt;/code&gt; rule&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;benchmarks&quot;&gt;Benchmarks&lt;/h3&gt;

&lt;p&gt;Let’s verify if all of this is working. Using the great &lt;a href=&quot;https://hackage.haskell.org/package/criterion&quot;&gt;Criterion library&lt;/a&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Algebra.Graph&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Control.DeepSeq&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Criterion.Main&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;IO&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;defaultMain&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bench&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;foldg&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nf&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foldg&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$!!&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;grInt&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bench&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;foldg . mapG&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nf&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;foldg&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mapG&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$!!&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;grInt&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bench&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;foldg . mapG . mapG&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nf&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;foldg&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mapG&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mapG&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$!!&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;grInt&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bench&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;mapG&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nf&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mapG&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$!!&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;grInt&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bench&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;mapG . mapG&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nf&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mapG&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mapG&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$!!&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;grInt&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;foldg&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;foldg&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foldg&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;mapG&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;mapG&apos;&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mapG&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;grInt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Graph&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;grInt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vertices&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9999&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;we will benchmark different combinations of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldg&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mapG&lt;/code&gt;.&lt;/p&gt;

&lt;h4 id=&quot;with-rewrite-rules&quot;&gt;With rewrite rules&lt;/h4&gt;
&lt;p&gt;Compiling with
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$  ghc -O Test.hs -ddump-rule-firings | grep Algebra.Graph&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Rule fired: mapG (Algebra.Graph)
Rule fired: foldg/buildG (Algebra.Graph)
Rule fired: mapG (Algebra.Graph)
Rule fired: mapG (Algebra.Graph)
Rule fired: foldg/buildG (Algebra.Graph)
Rule fired: mapFB/mapFB (Algebra.Graph)
Rule fired: mapG (Algebra.Graph)
Rule fired: mapG (Algebra.Graph)
Rule fired: foldg/buildG (Algebra.Graph)
Rule fired: mapFB/mapFB (Algebra.Graph)
Rule fired: foldg/buildG (Algebra.Graph)
Rule fired: foldg/mapGFB (Algebra.Graph)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So our rules are doing something… Are they doing it right ?:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;benchmarking foldg
time                 96.62 μs   (96.26 μs .. 97.09 μs)
[...]

benchmarking foldg . mapG
time                 94.05 μs   (93.90 μs .. 94.22 μs)
[...]

benchmarking foldg . mapG . mapG
time                 94.57 μs   (94.39 μs .. 94.79 μs)
[...]

benchmarking mapG
time                 207.6 μs   (205.9 μs .. 209.8 μs)
[...]

benchmarking mapG . mapG
time                 201.2 μs   (199.9 μs .. 203.2 μs)
[...]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The rules are working! &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldg&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldg . mapG&lt;/code&gt; are taking almost the same time to run. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mapG&lt;/code&gt; composition was also optimized away!&lt;/p&gt;

&lt;h4 id=&quot;without-the-rules&quot;&gt;Without the rules&lt;/h4&gt;

&lt;p&gt;But are we just lucky ?
Let’s try without the rewrite rules:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$ ghc -O Test.hs -fno-enable-rewrite-rules&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;benchmarking foldg
time                 95.36 μs   (95.04 μs .. 95.62 μs)
[...]

benchmarking foldg . mapG
time                 221.5 μs   (221.3 μs .. 221.8 μs)
[...]

benchmarking foldg . mapG . mapG
time                 398.3 μs   (397.4 μs .. 399.0 μs)
[...]

benchmarking mapG
time                 201.5 μs   (201.4 μs .. 201.6 μs)
[...]

benchmarking mapG . mapG
time                 348.6 μs   (348.5 μs .. 348.7 μs)
[...]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There is no luck here :) That was effectively the rewrite rules that optimizes the expressions.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build&lt;/code&gt; technique can be used to optimize user code with many structures with a custom &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fold&lt;/code&gt;, for example with alga’s graphs, but certainly for many others data-type. Also note that almost any function based on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foldg&lt;/code&gt; and of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Graph a -&amp;gt; Graph b&lt;/code&gt; can be optimized, not only &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mapG&lt;/code&gt; (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;induce&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transpose&lt;/code&gt; composition can be optimized to same way).&lt;/p&gt;</content><author><name></name></author><category term="Haskell" /><summary type="html">Introduction</summary></entry><entry><title type="html">GSoC 2018 results</title><link href="https://blog.nyarlathotep.one/2018/08/gsoc-results/" rel="alternate" type="text/html" title="GSoC 2018 results" /><published>2018-08-06T00:00:00+02:00</published><updated>2018-08-06T00:00:00+02:00</updated><id>https://blog.nyarlathotep.one/2018/08/gsoc-results</id><content type="html" xml:base="https://blog.nyarlathotep.one/2018/08/gsoc-results/">&lt;h2 id=&quot;the-project&quot;&gt;The project&lt;/h2&gt;

&lt;p&gt;The goal of this summer of code project was dual:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Write and use a benchmarking-suite for standard graphs libraries in Haskell.&lt;/li&gt;
  &lt;li&gt;Improve &lt;a href=&quot;https://github.com/snowleopard/alga&quot;&gt;Alga&lt;/a&gt;’s performances.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The summary of the project can be found at &lt;a href=&quot;https://summerofcode.withgoogle.com/projects/#5856533557018624&quot;&gt;https://summerofcode.withgoogle.com/projects/#5856533557018624&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;the-beginning&quot;&gt;The beginning&lt;/h2&gt;

&lt;p&gt;During the community bonding period, I sent some patches to &lt;a href=&quot;https://github.com/patrickdoc/hash-graph&quot;&gt;hash-graph&lt;/a&gt; and &lt;a href=&quot;https://github.com/haskell/fgl&quot;&gt;FGL&lt;/a&gt; while starting the benchmarking-suite. I also looked at some issues in Alga’s repository.&lt;/p&gt;

&lt;p&gt;The community was very warm and helped me even with my newcomer questions, which is always pleasant!&lt;/p&gt;

&lt;h2 id=&quot;the-benchmarking-suite&quot;&gt;The benchmarking suite&lt;/h2&gt;

&lt;p&gt;The suite is currently benchmarking 4 libraries:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://hackage.haskell.org/package/algebraic-graphs&quot;&gt;Alga (algebraic-graphs)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://hackage.haskell.org/package/containers&quot;&gt;Data.Graph from containers&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://hackage.haskell.org/package/fgl&quot;&gt;Fgl&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/patrickdoc/hash-graph&quot;&gt;Hash-Graph (not yet on Hackage)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With 18 functions.&lt;/p&gt;

&lt;p&gt;Results can be found at: &lt;a href=&quot;https://github.com/haskell-perf/graphs/tree/master/results&quot;&gt;https://github.com/haskell-perf/graphs/tree/master/results&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The main chart:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/haskell-perf/graphs/master/results/TIME.svg?sanitize=true&quot; alt=&quot;svg&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I wrote some comments &lt;a href=&quot;https://blog.nyarlathotep.one/2018/07/benchmarking-haskell-graph-libraries/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I used the great &lt;a href=&quot;http://www.serpentine.com/criterion/&quot;&gt;criterion&lt;/a&gt; to benchmark time and &lt;a href=&quot;https://hackage.haskell.org/package/weigh&quot;&gt;weigh&lt;/a&gt; for space usage.&lt;/p&gt;

&lt;h3 id=&quot;functionalities&quot;&gt;Functionalities&lt;/h3&gt;

&lt;p&gt;Using different parameters you can (at run-time):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Choose on which standard graphs (and their size) functions will be benchmarked.&lt;/li&gt;
  &lt;li&gt;Choose if you want to include the graph-creation time.&lt;/li&gt;
  &lt;li&gt;Choose specifically libraries/functions to be benchmarked.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It features different renderers:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;In plain text&lt;/li&gt;
  &lt;li&gt;In markdown&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And different analysis tools:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A summary that displays the fastest functions.&lt;/li&gt;
  &lt;li&gt;An abstract calculating a ratio between the largest benchmarks.&lt;/li&gt;
  &lt;li&gt;A quick comparison, when benchmarking two libraries, to say at a glance which one was faster.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Full usage instructions can be found in &lt;a href=&quot;https://github.com/haskell-perf/graphs/&quot;&gt;https://github.com/haskell-perf/graphs/&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;flags&quot;&gt;Flags&lt;/h3&gt;

&lt;p&gt;The suite is easily configurable at build-time. You can disable a library (and thus not depend on it) or a functionality using cabal flags.&lt;/p&gt;

&lt;h3 id=&quot;chart&quot;&gt;Chart&lt;/h3&gt;

&lt;p&gt;As requested by a reddit user, I have implemented a chart renderer using the great &lt;a href=&quot;https://github.com/timbod7/haskell-chart/wiki&quot;&gt;Chart&lt;/a&gt; library.&lt;/p&gt;

&lt;p&gt;It was a hard time, because of the little error bars which are not implemented by default in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Chart&lt;/code&gt; library.&lt;/p&gt;

&lt;h2 id=&quot;alga&quot;&gt;Alga&lt;/h2&gt;

&lt;h3 id=&quot;tutorial&quot;&gt;Tutorial&lt;/h3&gt;

&lt;p&gt;I wrote a little tutorial for newcomers to Alga. It can be found here: &lt;a href=&quot;https://nobrakal.github.io/alga-tutorial/&quot;&gt;https://nobrakal.github.io/alga-tutorial/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Written in LaTex and converted to HTML using the great (haskell-powered) &lt;a href=&quot;https://pandoc.org/&quot;&gt;pandoc&lt;/a&gt;. It means that one can easily produce a PDF file out of the code or modify the text quickly without dealing with HTML.&lt;/p&gt;

&lt;h3 id=&quot;agda&quot;&gt;Agda&lt;/h3&gt;

&lt;p&gt;I have made a little incursion in the proofs of the algebra of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Alga&lt;/code&gt; formalized in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;agda&lt;/code&gt;. I didn’t know this language and I learned a lot! I only proved a little axiom and failed to prove a bigger theorem, the full story is &lt;a href=&quot;https://blog.nyarlathotep.one/2018/06/trying-to-prove-an-algas-axiom-a-tale-of-a-weekend/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;optimizations&quot;&gt;Optimizations&lt;/h3&gt;

&lt;p&gt;A big part of optimizations was made using GHC techniques like rewrite rules, specialization and inlining. I have made a summary of what I have learned &lt;a href=&quot;https://blog.nyarlathotep.one/2018/07/ghc-one-compiler-to-rule-them-all/&quot;&gt;here&lt;/a&gt; to help others.
This work was mainly made in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Algebra.Graph&lt;/code&gt; module.&lt;/p&gt;

&lt;h3 id=&quot;regression-suite&quot;&gt;Regression suite&lt;/h3&gt;

&lt;p&gt;I have made a little &lt;a href=&quot;https://github.com/nobrakal/benchAlgaPr&quot;&gt;script&lt;/a&gt; that change the benchmarking-suite into a regression suite specialized for Alga. It compares two states of the Alga repository (like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt; and another branch being under a pull request).
It is highly tricky (in fact it is a suite of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sed&lt;/code&gt; commands) but very useful.
It can be done for any other graph library. Feel free to ask!&lt;/p&gt;

&lt;h2 id=&quot;what-is-left&quot;&gt;What is left&lt;/h2&gt;

&lt;p&gt;As always, there is some work left. Mainly I have opened some issues on Alga that I was not able to close yet.
There is also some code cleanup to do in the benchmarking suite as well as in the regression suite for Alga.&lt;/p&gt;

&lt;p&gt;If you find any missing features, don’t hesitate to tell me, I will be glad to help.&lt;/p&gt;

&lt;h2 id=&quot;feelings&quot;&gt;Feelings&lt;/h2&gt;

&lt;p&gt;After this list, I want to say that I had a very good time doing this Google Summer of Code. I think I learned more about functional programming during these three months than during two years in a bachelor of computer science.
Moreover, the Haskell community (which I observed through reddit) is extraordinary kind.&lt;/p&gt;

&lt;p&gt;I will be happy to continue the work started here, as I became a maintainer of alga :)&lt;/p&gt;

&lt;h2 id=&quot;thanks&quot;&gt;Thanks&lt;/h2&gt;

&lt;p&gt;I want to really thank Andrey Mokhov for his active and very useful mentorship! All of this project would not be what it is without his support and wise pieces of advice.&lt;/p&gt;

&lt;p&gt;Also, thanks to the entire Haskell community for its encouragements and critics.&lt;/p&gt;</content><author><name></name></author><category term="GSoC2018" /><summary type="html">The project</summary></entry><entry><title type="html">GHC, One compiler to RULE them all</title><link href="https://blog.nyarlathotep.one/2018/07/ghc-one-compiler-to-rule-them-all/" rel="alternate" type="text/html" title="GHC, One compiler to RULE them all" /><published>2018-07-20T00:00:00+02:00</published><updated>2018-07-20T00:00:00+02:00</updated><id>https://blog.nyarlathotep.one/2018/07/ghc-one-compiler-to-rule-them-all</id><content type="html" xml:base="https://blog.nyarlathotep.one/2018/07/ghc-one-compiler-to-rule-them-all/">&lt;p&gt;I am using some GHC pragmas to optimize &lt;a href=&quot;https://github.com/snowleopard/alga&quot;&gt;alga&lt;/a&gt; and I must admit that they are very powerful. On the wise counsel of one of my GSoC mentors, A. Mokhov, here is a little summary of what I discovered, as this can help others.&lt;/p&gt;

&lt;h2 id=&quot;ghc-is-the-employee-you-need&quot;&gt;GHC is the employee you need&lt;/h2&gt;

&lt;p&gt;First of all, it is important to understand the power of GHC.&lt;/p&gt;

&lt;p&gt;As a Haskell compiler, GHC is already great, but it is greater than that because it can &lt;em&gt;optimize&lt;/em&gt; your code.&lt;/p&gt;

&lt;p&gt;For example, let us consider &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;times4List&lt;/code&gt; that multiply by 4 every member of a list of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Int&lt;/code&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;times2Times2List&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;times2Times2List&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Obviously, this definition is equivalent to&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;times4List&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;times4List&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The second definition should be faster, because it traverses the list once, while the first do it 2 times.&lt;/p&gt;

&lt;p&gt;Let us try with a very simple code to benchmark this, using &lt;a href=&quot;https://hackage.haskell.org/package/criterion&quot;&gt;Criterion&lt;/a&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Criterion.Main&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;IO&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;defaultMain&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bench&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;times2Times2List&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nf&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;times2Times2List&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bench&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;times4List&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nf&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;times4List&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;times2Times2List&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;times2Times2List&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;times4List&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;times4List&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If we compile the code &lt;em&gt;without&lt;/em&gt; optimization, it produces:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;benchmarking times2Times2List
time                 726.9 μs   (707.4 μs .. 749.2 μs)
[...]
benchmarking times4List
time                 397.2 μs   (396.0 μs .. 398.5 μs)
[...]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So as expected, the first is slower.&lt;/p&gt;

&lt;p&gt;Now if we recompile the same file but asking GHC to optimize our code (with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-O&lt;/code&gt;):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;benchmarking times2Times2List
time                 215.0 μs   (214.9 μs .. 215.2 μs)
[...]
benchmarking times4List
time                 212.2 μs   (211.9 μs .. 212.6 μs)
[...]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So GHC, among other optimizations, merged the two maps.&lt;/p&gt;

&lt;h2 id=&quot;ghcs-rules-pragmas&quot;&gt;GHC’s RULEs pragmas&lt;/h2&gt;

&lt;p&gt;But how GHC figured out to combine the two maps? With a cool pragma: the &lt;a href=&quot;https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#rewrite-rules&quot;&gt;rewrites rules&lt;/a&gt;. It is very simple and yet very powerful.&lt;/p&gt;

&lt;p&gt;Let us see what optimized the two first examples (this is not true, you can see the real RULES used &lt;a href=&quot;https://hackage.haskell.org/package/base-4.11.1.0/docs/src/GHC.Base.html#map&quot;&gt;here&lt;/a&gt;, but we will assume it for the sake of simplicity).&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;cp&quot;&gt;{-# RULES
  &quot;map/map&quot; forall f g xs. map f (map g xs) = map (f.g) xs
 #-}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Basically, this rule is telling GHC to change &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;map f (map g xs)&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;map (f.g) xs&lt;/code&gt; when types match.&lt;/p&gt;

&lt;h3 id=&quot;everything-is-important&quot;&gt;Everything is important&lt;/h3&gt;

&lt;p&gt;The actual little words “when types match” lead to something very cool: you can specialize a function to a specific type.&lt;/p&gt;

&lt;p&gt;Imagine you have a function that internally deals with &lt;a href=&quot;http://hackage.haskell.org/package/containers-0.6.0.1/docs/Data-Set.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Data.Set&lt;/code&gt;&lt;/a&gt; to count the unique elements of a list:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;qualified&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Data.Set&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Set&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;countUniques&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Ord&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;countUniques&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fromList&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;It is well known that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Data.IntSet&lt;/code&gt; is faster than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Data.Set&lt;/code&gt;. So why not use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IntSet&lt;/code&gt; when possible? And, even better, is it possible to do the change “behind” the user’s back, so the user does not have to use the specialized version “by hand”?&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;kr&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Test&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;

&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;qualified&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Data.Set&lt;/span&gt;   &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Set&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;qualified&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Data.IntSet&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IntSet&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;countUniques&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Ord&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;countUniques&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fromList&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{-# RULES
  &quot;countUniques/Int&quot; countUniques = countUniquesInt
  #-}&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;{-# INLINE [1] countUniques #-}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;countUniquesInt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;countUniquesInt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;IntSet&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;IntSet&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fromList&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now, you are telling GHC to change &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;countUniques&lt;/code&gt; by the faster &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;countUniquesInt&lt;/code&gt; when possible, &lt;strong&gt;even is the user’s code&lt;/strong&gt; (do not pay attention to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INLINE&lt;/code&gt; pragma, it is discussed after).&lt;/p&gt;

&lt;p&gt;In two other files, here is some benchmarking code:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Alone.hs&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;kr&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Alone&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;

&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;qualified&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Data.Set&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Set&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;countUniquesP&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Ord&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;countUniquesP&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fromList&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;Main.hs&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Test&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Alone&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Criterion.Main&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;aListOfInt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;aListOfInt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;IO&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;defaultMain&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bench&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;countUniques&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nf&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;countUniques&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;aListOfInt&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bench&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;countUniquesP&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nf&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;countUniquesP&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;aListOfInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Compiling with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ghc Main.hs -O&lt;/code&gt; and running it gives:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;benchmarking countUniques
time                 530.9 μs   (528.6 μs .. 533.9 μs)
[...]

benchmarking countUniquesP
time                 836.3 μs   (834.0 μs .. 838.2 μs)
[...]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Using the rewrite rule, we get more than a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;50%&lt;/code&gt; speedup!&lt;/p&gt;

&lt;p&gt;Try to remove the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INLINE&lt;/code&gt; line in my previous example and re-build using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ghc Main.hs -O&lt;/code&gt;. Ghc will complain about an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INLINE&lt;/code&gt; pragma, and in performances:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;benchmarking countUniques
time                 880.6 μs   (855.6 μs .. 907.1 μs)
[...]

benchmarking countUniquesP
time                 885.0 μs   (858.8 μs .. 910.2 μs)
[...]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;countUniques/Int&lt;/code&gt; rule has not fired!&lt;/p&gt;

&lt;p&gt;So what did the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INLINE&lt;/code&gt; pragma?&lt;/p&gt;

&lt;h2 id=&quot;inline-please&quot;&gt;INLINE, please&lt;/h2&gt;

&lt;p&gt;Now let’s say that you are going to use a strange library which provide:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;times2List&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;times2List&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Then one can write:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;times4List&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;times4List&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;times2List&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;So does the optimization occur?&lt;/p&gt;

&lt;p&gt;That is the pretty part: &lt;em&gt;yes&lt;/em&gt; it actually takes place. To help to figure out such optimizations, GHC &lt;strong&gt;inlines&lt;/strong&gt; your code. Because Haskell is pure, one can replace a function by its definition.&lt;/p&gt;

&lt;p&gt;If GHC estimate that it worth it, the compiler will replace your function by its definition. And you guessed it, GHC tries to apply RULES at each pass. So conceptually, GHC translates:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;times4List&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;times4List&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;times2List&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;in&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;times4List&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;times4List&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;and apply the previous rule:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;times4List&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;times4List&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;So GHC does this pretty well itself, but you can sometimes want to override its default behavior (in fact, it almost every time inlines small functions, but is more reluctant to inline big functions). That is what &lt;a href=&quot;https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#inline-noinline-pragma&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INLINE&lt;/code&gt; pragma&lt;/a&gt; is made for (and the corresponding &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NOINLINE&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Adding&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;cp&quot;&gt;{-# INLINE myComplicatedFunc #-}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;will make GHC very keen to inline &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;myComplicatedFunc&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;inlining-phase&quot;&gt;Inlining phase&lt;/h3&gt;

&lt;p&gt;You can even add the phase on which you want the inlining to be done. Currently, GHC runs 3 phases (numbered from 2 to 0) in which it tries to inline and applies rewrite rules. The syntax is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{-# INLINE [k] myComplicatedFunc #-}&lt;/code&gt;, which, quoting GHC manual, means:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;do not inline &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;myComplicatedFunc&lt;/code&gt; until phase k, but from phase k onwards be very keen to inline it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Why do we care? Because of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RULES&lt;/code&gt;! If we INLINE a function too early in the process, related &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RULES&lt;/code&gt; might not fire. So it is always a good idea to specify an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INLINE&lt;/code&gt; pragma with phase control when using rules, to ensure that nothing is done too early preventing your super rule to fire!&lt;/p&gt;

&lt;p&gt;So what happened to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;countUniques&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;Because its definition is very simple, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GHC&lt;/code&gt; inlined it and prevented the RULE to fire!&lt;/p&gt;

&lt;p&gt;Adding &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{-# INLINE [1] countUniques #-}&lt;/code&gt; ensure that GHC will not inline &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;countUniques&lt;/code&gt; too early and thus that the RULE will fire.&lt;/p&gt;

&lt;h3 id=&quot;why-not-everything-is-inlined&quot;&gt;Why not everything is inlined?&lt;/h3&gt;

&lt;p&gt;Because it is sometimes not possible (for a recursive function for example) or sometimes useless (transforming &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;map f xs&lt;/code&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;map (\x -&amp;gt; fbody x) xs&lt;/code&gt; is not useful) and this takes time to the compiler. Moreover inlining everything when it is not needed can lead to an enormous amount of code.&lt;/p&gt;

&lt;h2 id=&quot;specialize-yourself&quot;&gt;SPECIALIZE yourself&lt;/h2&gt;

&lt;p&gt;One other pragma was once a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RULE&lt;/code&gt; but is now a pragma in full: &lt;a href=&quot;https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#specialize-pragma&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SPECIALIZE&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When you have a class constraint in a function, for example with:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;plusTwoRec&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Num&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plusTwoRec&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;[]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plusTwoRec&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;plusTwoRec&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xs&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;(It is basically &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;map (+2)&lt;/code&gt; but we will not use this definition either GHC will inline it too quickly).&lt;/p&gt;

&lt;p&gt;The function produced by GHC is containing another argument called a dictionary carrying information about class methods (here the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Num&lt;/code&gt; class). Adding an argument and having to lookup through it takes time. So you can &lt;em&gt;specialize&lt;/em&gt; the function using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SPECIALIZE&lt;/code&gt; pragma.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;cp&quot;&gt;{-# SPECIALIZE plusTwoRec :: [Int] -&amp;gt; [Int] #-}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This will create another function, with the same code than the original &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;plusTwoRec&lt;/code&gt; &lt;em&gt;but&lt;/em&gt; with the specialized type (and thus, without the dictionary) and a rule to change the two functions when types match.&lt;/p&gt;

&lt;p&gt;To benchmark all of this, we will use three files:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Alone.hs&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;kr&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Alone&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;plusTwoRecP&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Num&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plusTwoRecP&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;[]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plusTwoRecP&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;plusTwoRecP&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xs&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;Todo.hs&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;kr&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Todo&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;

&lt;span class=&quot;cp&quot;&gt;{-# SPECIALIZE plusTwoRec :: [Int] -&amp;gt; [Int] #-}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plusTwoRec&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Num&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plusTwoRec&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;[]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plusTwoRec&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;plusTwoRec&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xs&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;Main.hs&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Todo&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Alone&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Criterion.Main&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;aListOfInt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;aListOfInt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;IO&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;defaultMain&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bench&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;plusTwoRec&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nf&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;plusTwoRec&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;aListOfInt&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bench&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;plusTwoRecP&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nf&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;plusTwoRecP&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;aListOfInt&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;(Merging &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Alone.hs&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Todo.hs&lt;/code&gt; prevent the rule to fire in GHC 8.4.3, this will be corrected in a next release (see &lt;a href=&quot;https://ghc.haskell.org/trac/ghc/ticket/15445&quot;&gt;https://ghc.haskell.org/trac/ghc/ticket/15445&lt;/a&gt;)).&lt;/p&gt;

&lt;p&gt;Compiling with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ghc Main.hs -O&lt;/code&gt; and running it:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;benchmarking plusTwoRec
time                 187.3 μs   (184.6 μs .. 190.8 μs)
[...]

benchmarking plusTwoRecP
time                 396.0 μs   (393.9 μs .. 398.3 μs)
[...]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Compiling with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ghc Main.hs -O -fno-enable-rewrite-rules&lt;/code&gt; and running it:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;benchmarking plusTwoRec
time                 396.3 μs   (394.4 μs .. 398.4 μs)
[...]

benchmarking plusTwoRecP
time                 395.3 μs   (393.8 μs .. 397.7 μs)
[...]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Specialization is a great way to optimize a polymorphic library when you know that it will be used mostly with one type.&lt;/p&gt;

&lt;p&gt;Some examples of specialization can be found in the actual &lt;a href=&quot;http://hackage.haskell.org/package/base-4.11.0.0/docs/src/GHC.Base.html#fail&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GHC.Base&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;why-not-everything-is-specialized&quot;&gt;Why not everything is specialized?&lt;/h3&gt;

&lt;p&gt;When you have to deal with the outside you cannot tell in advance what types will your user need; moreover creating a specialized function takes space and doing this too much can create a very big library.&lt;/p&gt;

&lt;h2 id=&quot;inspect-the-core&quot;&gt;Inspect the core&lt;/h2&gt;

&lt;p&gt;But how to figure out what really does GHC? You can inspect the code produced after the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inline/rules&lt;/code&gt; passes by passing &lt;a href=&quot;http://downloads.haskell.org/~ghc/latest/docs/html/users_guide/debugging.html#ghc-flag--ddump-simpl&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-ddump-simpl&lt;/code&gt;&lt;/a&gt; to it. It will throw a lot of code, not always very understandable, but useful for comparison.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;GHC is like your grandpa’s old car. When you are using it, it goes well, but your grandpa was able to make miracles with this old thing! How? Only because he knew how to use it properly :) .&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: This article presents a very (very) superficial point of view about these pragmas. Please don’t hesitate to check the &lt;a href=&quot;https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html&quot;&gt;GHC manual related chapter&lt;/a&gt; or comment if you find something strange!&lt;/em&gt;&lt;/p&gt;</content><author><name></name></author><category term="GSoC2018" /><category term="Haskell" /><summary type="html">I am using some GHC pragmas to optimize alga and I must admit that they are very powerful. On the wise counsel of one of my GSoC mentors, A. Mokhov, here is a little summary of what I discovered, as this can help others.</summary></entry><entry><title type="html">Benchmarking Haskell graph libraries</title><link href="https://blog.nyarlathotep.one/2018/07/benchmarking-haskell-graph-libraries/" rel="alternate" type="text/html" title="Benchmarking Haskell graph libraries" /><published>2018-07-05T00:00:00+02:00</published><updated>2018-07-05T00:00:00+02:00</updated><id>https://blog.nyarlathotep.one/2018/07/benchmarking-haskell-graph-libraries</id><content type="html" xml:base="https://blog.nyarlathotep.one/2018/07/benchmarking-haskell-graph-libraries/">&lt;h2 id=&quot;the-results&quot;&gt;The results&lt;/h2&gt;

&lt;p&gt;The main results are here &lt;a href=&quot;https://github.com/haskell-perf/graphs/blob/master/results/&quot;&gt;https://github.com/haskell-perf/graphs/blob/master/results/&lt;/a&gt; with some explanations on the benchmarks themselves.&lt;/p&gt;

&lt;p&gt;The following of this article is some comments on these results.&lt;/p&gt;

&lt;p&gt;One of the goals of &lt;a href=&quot;https://summerofcode.withgoogle.com/projects/#5856533557018624&quot;&gt;my Google Summer of Code 2018 project&lt;/a&gt; was to make a benchmark table of the four main graphs libraries in Haskell:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://hackage.haskell.org/package/algebraic-graphs&quot;&gt;Alga (algebraic-graphs)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://hackage.haskell.org/package/containers&quot;&gt;Data.Graph from containers&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://hackage.haskell.org/package/fgl&quot;&gt;Fgl&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/patrickdoc/hash-graph&quot;&gt;Hash-Graph (not yet on Hackage)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The results are in &lt;a href=&quot;https://github.com/haskell-perf/graphs/&quot;&gt;https://github.com/haskell-perf/graphs/&lt;/a&gt; where is stored the code of the benchmarking suite.&lt;/p&gt;

&lt;p&gt;If you find a result awkward or faulty, feel free to open an issue at &lt;a href=&quot;https://github.com/haskell-perf/graphs/issues&quot;&gt;https://github.com/haskell-perf/graphs/issues&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Also please don’t hesitate to tweak the benchmarking suite and try yourself to produce some numbers, it is made for it!&lt;/p&gt;

&lt;h2 id=&quot;preliminary-comment&quot;&gt;Preliminary comment&lt;/h2&gt;

&lt;p&gt;These libraries are &lt;strong&gt;really&lt;/strong&gt; different, in their inner concept, and they have to be understood before starting an analysis:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Alga is based on a new way of viewing graphs, developed by Andrey Mokhov ( thanks to him for its feedback and help concerning the benchmarks ). It is recent: the first version was uploaded on Hackage on March, 24 2017. Alga represents graph in a functional, constructively way.&lt;/li&gt;
  &lt;li&gt;Containers is based on the very fast &lt;a href=&quot;http://hackage.haskell.org/package/array-0.5.2.0/docs/Data-Array.html&quot;&gt;immutable array&lt;/a&gt;, it implies that the bound of vertices is &lt;strong&gt;immutable&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;But everything is immutable in Haskell !&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You are right, but even if a list is immutable, you can expand a list (when adding an element). This is &lt;em&gt;not&lt;/em&gt; true for immutable arrays. Once it is created you cannot add keys to it: in fact it already contains every vertices between the given bounds; thus you cannot add vertices as you want. It is also the only implementation of graph to support only the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Int&lt;/code&gt; type for its vertices.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Fgl is an older try to make graph more “functional-friendly” (by Martin Erwig) with first Hackage version back in 2006 !&lt;/li&gt;
  &lt;li&gt;Hash-Graph is a try by Patrick Dougherty ( thanks to him for its feedback concerning the benchmarks ) to modernize the Fgl interface.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;what-to-expect&quot;&gt;What to expect&lt;/h3&gt;

&lt;p&gt;In time complexities, we will note:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;n&lt;/code&gt; for the number of vertices in the graph.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;s&lt;/code&gt; for the algebraic size of the graph. Actually for alga’s graphs in the main results, we have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;s = 2 * e&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;e&lt;/code&gt; the number of edges in the graph.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Alga does not assume any instance for its vertices so it cannot construct traditional efficient data-structures (like int-maps or hash-maps). This leads to a general complexity of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;O(s)&lt;/code&gt; for most of the functions (this is because of the way graphs are constructed from a list of edges. Using a more “alga” representation (like for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clique&lt;/code&gt;) can change this complexity to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;O(n)&lt;/code&gt;).&lt;/li&gt;
  &lt;li&gt;Fgl and Hash-Graph functions are almost always requiring either an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ord&lt;/code&gt; or a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Hashable&lt;/code&gt; instance for vertices, so they can build an efficient representation. This results to an average complexity of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;O(log(n))&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Containers is working only with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Int&lt;/code&gt; vertices so it can build very fast representation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That being said, lets analyze a bit the results.&lt;/p&gt;

&lt;h2 id=&quot;quick-analyze&quot;&gt;Quick Analyze&lt;/h2&gt;

&lt;h3 id=&quot;start-by-the-end-of-the-list&quot;&gt;Start by the end of the list&lt;/h3&gt;

&lt;p&gt;Lets starting by the end and take a look at the &lt;a href=&quot;https://github.com/haskell-perf/graphs/blob/master/results/TIME.md#creation&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;creation&lt;/code&gt;&lt;/a&gt; benchmark. Here there is no compromise:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Alga and Containers are the fastest.&lt;/li&gt;
  &lt;li&gt;Fgl and Hash-Graph are a bit behind.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Alga is building a “blind” representation (it does not check if you are adding an edge already here for example), so it is fast. Containers is fast thanks to its &lt;em&gt;array&lt;/em&gt;-based implementation. The last two are building a “clever” representation, so it takes more time. The next part will give them their reward.&lt;/p&gt;

&lt;h3 id=&quot;inspection-&quot;&gt;Inspection !&lt;/h3&gt;

&lt;p&gt;Graph inspection comprises functions like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;isEmpty&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hasVertex&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hasEdge&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;equality&lt;/code&gt;. &lt;a href=&quot;https://github.com/haskell-perf/graphs/blob/master/results/TIME.md#isempty&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;isEmpty&lt;/code&gt;&lt;/a&gt; is efficient for everyone. Problems are coming with &lt;a href=&quot;https://github.com/haskell-perf/graphs/blob/master/results/TIME.md#hasvertex&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hasVertex&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;Because Hash-Graph is representing graphs as an adjacency (hash-)map, its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hasVertex&lt;/code&gt; works almost in constant time (real complexity of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;O(log n)&lt;/code&gt;). Fgl works with int-maps, so it has also a complexity of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;O(log n)&lt;/code&gt;. Alga works in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;O(s)&lt;/code&gt;. Note that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hasVertex&lt;/code&gt; for Containers does not have any sense, since it does not make any difference between having a single vertex or not having it (its representation, an array, is a map with consecutive keys comprised between a pair of bounds).&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/haskell-perf/graphs/blob/master/results/TIME.md#equality&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;equality&lt;/code&gt;&lt;/a&gt; is one of the big advantages of Containers which handle the question very quickly. It is one of the problems of Alga which is, behind the scene, translating its representation to adjacency maps and then comparing them.&lt;/p&gt;

&lt;h3 id=&quot;graph-modification&quot;&gt;Graph modification&lt;/h3&gt;

&lt;p&gt;Graph inspection comprise functions like &lt;a href=&quot;https://github.com/haskell-perf/graphs/blob/master/results/TIME.md#addvertex&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;addVertex&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://github.com/haskell-perf/graphs/blob/master/results/TIME.md#removevertex&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;removeVertex&lt;/code&gt;&lt;/a&gt;, &lt;a href=&quot;https://github.com/haskell-perf/graphs/blob/master/results/TIME.md#addedge&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;addEdge&lt;/code&gt;&lt;/a&gt; or &lt;a href=&quot;https://github.com/haskell-perf/graphs/blob/master/results/TIME.md#removeedge&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;removeEdge&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As it was the case for creation, Alga is faster than Fgl and Hash-Graph for adding something (for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;addEdge&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;addVertex&lt;/code&gt;). But because removing something implies some inspection, Hash-Graph and Fgl takes the lead for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;removeVertex&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;removeEdge&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;algorithms&quot;&gt;Algorithms&lt;/h3&gt;

&lt;p&gt;One of the only comparable algorithm is &lt;a href=&quot;https://github.com/haskell-perf/graphs/blob/master/results/TIME.md#dff&quot;&gt;dff&lt;/a&gt;, which produces a forest obtained from a DFS (for Deep First Search) of each vertex. Containers is built for it: it is definitely faster.&lt;/p&gt;

&lt;p&gt;A little note about Alga which implement a &lt;a href=&quot;https://github.com/haskell-perf/graphs/blob/master/results/TIME.md#transpose&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transpose&lt;/code&gt;&lt;/a&gt; faster than Containers.&lt;/p&gt;

&lt;p&gt;Others traditional algorithms are often also implemented (like BFS), but because they not produce exactly the same data-structure at the end, they cannot be compared.&lt;/p&gt;

&lt;h3 id=&quot;un-creation&quot;&gt;Un-creation&lt;/h3&gt;

&lt;p&gt;You may want to get a list of vertices or edges in the graph, and libraries have fitting functions for this. It is graph-inspection related, so you could guess the result:&lt;/p&gt;

&lt;p&gt;Containers is the fastest, then come Hash-Graph, close to Fgl and then Alga.&lt;/p&gt;

&lt;h3 id=&quot;fgl-related&quot;&gt;Fgl related&lt;/h3&gt;

&lt;p&gt;Because Hash-Graph and Fgl implement almost the same API, they have some common functions related to the theory behind. This is the case for &lt;a href=&quot;https://github.com/haskell-perf/graphs/blob/master/results/TIME.md#mergecontext&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mergeContext&lt;/code&gt;&lt;/a&gt;. No surprises, Fgl was built on it, so it is faster than Hash-Graph.&lt;/p&gt;

&lt;h2 id=&quot;about-the-benchmarks&quot;&gt;About the benchmarks&lt;/h2&gt;

&lt;h3 id=&quot;the-creation-time&quot;&gt;The creation time&lt;/h3&gt;

&lt;p&gt;As said in the &lt;a href=&quot;https://github.com/haskell-perf/graphs/blob/master/results/README.md&quot;&gt;README&lt;/a&gt; of results, the benchmarks are obtained by constructing and fully evaluating a graph from a list of edges, passing it to the evaluated function and then fully evaluate the results. This clearly favor libraries with a “clever” representation and does not obviously represent every use cases. Thus we provide &lt;a href=&quot;https://github.com/haskell-perf/graphs/blob/master/results/TIME-creation.md&quot;&gt;https://github.com/haskell-perf/graphs/blob/master/results/TIME-creation.md&lt;/a&gt; which take into account the creation time. Alga is now becoming a serious competitor!&lt;/p&gt;

&lt;h3 id=&quot;the-representation-itself&quot;&gt;The representation itself&lt;/h3&gt;

&lt;p&gt;Alga is the only library for which the function that is creating a graph from a list of edges is not at all optimized; it results that the graph obtained is not very convenient to work with. Things are not the same when graphs are constructed “the alga way”. An example is taken with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clique&lt;/code&gt; which is a very “algebraic” structure. The main comment is that it reduces the gap between Alga and the others, but not always fills it. Results can be seen here: &lt;a href=&quot;https://github.com/haskell-perf/graphs/blob/master/results/TIME-extra.md&quot;&gt;https://github.com/haskell-perf/graphs/blob/master/results/TIME-extra.md&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;h3 id=&quot;a-summary-it-was-predictable&quot;&gt;A summary: It was predictable&lt;/h3&gt;

&lt;p&gt;Due to their inner differences, Alga is faster for the creation of a graph. Fgl and Hash-Graph are better for graph inspection (the two libraries are optimized for different things, pick what you need!). &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Data.Graph&lt;/code&gt; from Containers is almost everywhere faster, but it implies to work with very specific graphs (with an immutable set of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Int&lt;/code&gt; vertices).&lt;/p&gt;

&lt;h3 id=&quot;evaluate-your-need&quot;&gt;Evaluate your need&lt;/h3&gt;

&lt;p&gt;There is no an “always better choice” when dealing with graphs libraries in the Haskell ecosystem. Just evaluate your needs! There is some questions that you can ask yourself:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;What is the type of my vertices ? Does they have an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ord&lt;/code&gt; or a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Hashable&lt;/code&gt; instance ?&lt;/li&gt;
  &lt;li&gt;I am going to modify the graph a lot ?&lt;/li&gt;
  &lt;li&gt;I am going to inspect the graph a lot ?&lt;/li&gt;
  &lt;li&gt;What standard algorithms will I need ? Are they already efficiently implemented in a library ?&lt;/li&gt;
&lt;/ul&gt;</content><author><name></name></author><category term="GSoC2018" /><category term="Haskell" /><summary type="html">The results</summary></entry><entry><title type="html">Named things in Haskell</title><link href="https://blog.nyarlathotep.one/2018/05/named-things/" rel="alternate" type="text/html" title="Named things in Haskell" /><published>2018-05-14T00:00:00+02:00</published><updated>2018-05-14T00:00:00+02:00</updated><id>https://blog.nyarlathotep.one/2018/05/named-things</id><content type="html" xml:base="https://blog.nyarlathotep.one/2018/05/named-things/">&lt;p&gt;For my GSoC project, I have to deal with named things, and I tried to generalized the traditional &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(String,a)&lt;/code&gt; object and I came with an interesting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Named a&lt;/code&gt; data.&lt;/p&gt;

&lt;h2 id=&quot;the-problem&quot;&gt;The problem&lt;/h2&gt;

&lt;p&gt;We often deal with named things, on which we want to perform some operations, &lt;em&gt;without&lt;/em&gt; changing its name. For example, I want to benchmark libraries, so I will start with something like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(String, Benchmark)&lt;/code&gt;, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;String&lt;/code&gt; being the library name, and come out to a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(String, Double)&lt;/code&gt;, with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Double&lt;/code&gt; being the time of taken by the function.&lt;/p&gt;

&lt;p&gt;( For the sake of simplicity, lets imagine we have a function:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;bench&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Benchmark&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;IO&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Double&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;)&lt;/p&gt;

&lt;h2 id=&quot;the-named-data&quot;&gt;The Named Data&lt;/h2&gt;

&lt;p&gt;I started to write the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Named&lt;/code&gt; data:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;kr&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;and one needed instance:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;kr&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Show&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;show&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And then, the main idea: applying a function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f: a -&amp;gt; b&lt;/code&gt; to a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Named a&lt;/code&gt; will produce a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Named b&lt;/code&gt; &lt;em&gt;without changing the name&lt;/em&gt;. My Haskell alarms ringed and detected a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Functor&lt;/code&gt; instance:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;kr&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Functor&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;fmap&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Well, so thought I was able to write a pretty function like:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;benchN&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Benchmark&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;IO&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Double&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;But recall, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bench&lt;/code&gt; is of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Benchmark -&amp;gt; IO Double&lt;/code&gt;, so, using only &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fmap&lt;/code&gt; will lead to:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;uglyBenchN&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Benchmark&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;IO&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Double&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;uglyBenchN&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fmap&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bench&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;So…&lt;/p&gt;

&lt;h3 id=&quot;the-traversable-instance&quot;&gt;The Traversable instance&lt;/h3&gt;

&lt;p&gt;The solution is to provide &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sequence :: Monad m =&amp;gt; Named (m a) -&amp;gt; m (Named a)&lt;/code&gt;, which is inside the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Traversable&lt;/code&gt; class. As its type says, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sequence&lt;/code&gt; will “strip-out” the monadic effect. So we have:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;kr&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Foldable&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;foldMap&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;

&lt;span class=&quot;kr&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Traversable&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;-- Applicative f =&amp;gt; Named (f a) -&amp;gt; f (Named a) &lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;sequenceA&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And poof, I am able to write:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;notSoUglybenchN&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Benchmark&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;IO&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Double&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;notSoUglybenchN&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sequence&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fmap&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bench&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Because this is a common thing to do, we can use a classic function, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;traverse&lt;/code&gt;, and hence:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;benchN&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Benchmark&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;IO&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Double&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;benchN&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;traverse&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bench&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Hooray ! But can we do better ? &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Named&lt;/code&gt; seems a pretty interesting object…&lt;/p&gt;

&lt;h3 id=&quot;is-named-a-monad--answer-no-it-is-a-comonad&quot;&gt;Is Named a Monad ? (Answer, no it is a CoMonad)&lt;/h3&gt;

&lt;p&gt;An interesting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Functor&lt;/code&gt; is sometimes a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Monad&lt;/code&gt;. So I started my checklist: to provide a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Monad&lt;/code&gt; I have to provide the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;return&lt;/code&gt; and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bind&lt;/code&gt; function:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;I don’t have a standard way to name things, and neither to get a name out of two named things… But I can easily strip out the name, and conserve the name:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;notReturn&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;notBind&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;It seems pretty much like something dual to a monad. And this is called a &lt;a href=&quot;http://hackage.haskell.org/package/comonad/docs/Control-Comonad.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Comonad&lt;/code&gt;&lt;/a&gt; :)&lt;/p&gt;

&lt;p&gt;The instance definition:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;kr&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Comonad&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;-- Named a -&amp;gt; a&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;extract&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;-- Named a -&amp;gt; (Named a -&amp;gt; b) -&amp;gt; Named b &lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;named&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;show&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;named&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;named&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Well we have a Comonad instance, we can redefine the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Eq&lt;/code&gt; instance, given a little function:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;n&quot;&gt;liftExtract&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Comonad&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;liftExtract&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;extract&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;extract&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;kr&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Eq&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Eq&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;liftExtract&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;liftExtract&lt;/code&gt; can in fact be used to define every &lt;a href=&quot;https://hackage.haskell.org/package/transformers-0.5.0.0/docs/Data-Functor-Classes.html&quot;&gt;lifted instances of transformers&lt;/a&gt;…&lt;/p&gt;

&lt;p&gt;And can even redefine the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Functor&lt;/code&gt; instance:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-haskell&quot; data-lang=&quot;haskell&quot;&gt;&lt;span class=&quot;kr&quot;&gt;instance&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Functor&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;fmap&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;liftW&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;</content><author><name></name></author><category term="GSoC2018" /><category term="Haskell" /><summary type="html">For my GSoC project, I have to deal with named things, and I tried to generalized the traditional (String,a) object and I came with an interesting Named a data.</summary></entry><entry><title type="html">GSoC 2018 - The plan</title><link href="https://blog.nyarlathotep.one/2018/04/gsoc-the-plan/" rel="alternate" type="text/html" title="GSoC 2018 - The plan" /><published>2018-04-26T00:00:00+02:00</published><updated>2018-04-26T00:00:00+02:00</updated><id>https://blog.nyarlathotep.one/2018/04/gsoc-the-plan</id><content type="html" xml:base="https://blog.nyarlathotep.one/2018/04/gsoc-the-plan/">&lt;p&gt;I was admitted for the Google Summer of Code 2018 with my project: &lt;a class=&quot;md-soc-theme&quot; href=&quot;https://summerofcode.withgoogle.com/projects/#5856533557018624&quot; target=&quot;_self&quot;&gt;Benchmarking graph libraries and optimising algebraic graphs&lt;/a&gt;, for the Haskell organization and under the wise supervision of &lt;a href=&quot;https://blogs.ncl.ac.uk/andreymokhov/&quot;&gt;Andrey Mokhov&lt;/a&gt; and &lt;a href=&quot;http://aloiscochard.github.io/&quot;&gt;Aloïs Cochard&lt;/a&gt;. So I am going to work for the next 3 months on graph libraries in the Haskell ecosystem. The work will be done in two mains repositories:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;For the graph benchmarking suite: &lt;a href=&quot;https://github.com/haskell-perf/graphs&quot;&gt;https://github.com/haskell-perf/graphs&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;For alga: &lt;a href=&quot;https://github.com/snowleopard/alga&quot;&gt;https://github.com/snowleopard/alga&lt;/a&gt; And of course, regular updates will come here about the code progress :)&lt;/li&gt;
&lt;/ul&gt;</content><author><name></name></author><category term="GSoC2018" /><summary type="html">I was admitted for the Google Summer of Code 2018 with my project: Benchmarking graph libraries and optimising algebraic graphs, for the Haskell organization and under the wise supervision of Andrey Mokhov and Aloïs Cochard. So I am going to work for the next 3 months on graph libraries in the Haskell ecosystem. The work will be done in two mains repositories: For the graph benchmarking suite: https://github.com/haskell-perf/graphs For alga: https://github.com/snowleopard/alga And of course, regular updates will come here about the code progress :)</summary></entry></feed>