<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Oleg Nizhnik on Medium]]></title>
        <description><![CDATA[Stories by Oleg Nizhnik on Medium]]></description>
        <link>https://medium.com/@odomontois?source=rss-fe18154433bd------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/0*z0WaNgySal5rsf6S.</url>
            <title>Stories by Oleg Nizhnik on Medium</title>
            <link>https://medium.com/@odomontois?source=rss-fe18154433bd------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 18:24:29 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@odomontois/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[About capture checking]]></title>
            <link>https://medium.com/@odomontois/several-days-ago-we-saw-the-new-experimental-feature-called-capture-checking-was-announced-in-e4aa9bc4b3d1?source=rss-fe18154433bd------2</link>
            <guid isPermaLink="false">https://medium.com/p/e4aa9bc4b3d1</guid>
            <category><![CDATA[lifetime]]></category>
            <category><![CDATA[capture-checking]]></category>
            <category><![CDATA[scala-3]]></category>
            <category><![CDATA[resources]]></category>
            <dc:creator><![CDATA[Oleg Nizhnik]]></dc:creator>
            <pubDate>Mon, 14 Feb 2022 12:54:58 GMT</pubDate>
            <atom:updated>2022-02-14T14:19:49.144Z</atom:updated>
            <content:encoded><![CDATA[<p>in scala 3</p><p>Several days ago, we saw the new experimental feature called “<a href="https://dotty.epfl.ch/reference/experimental/cc.html">capture checking</a>” was announced in <a href="https://twitter.com/odersky/status/1491693322573864960">the tweet</a> by M. Odersky.</p><p>This feature is a new chapter in a decade-long struggle for adding something like an effect system to scala 3. It has some similarities with the <a href="https://arxiv.org/abs/2103.06127">linear constraints</a> proposal for Haskell and rust <a href="https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html">lifetimes</a>.</p><h3>Disclaimer:</h3><p><em>all of the code snippets here are not type-checked and should be considered scala-like pseudo-language</em></p><h3>Effect systems</h3><p>Effect system is some form of metainformation, usually inside the type system. It alerts and checks that the runtime meaning or other semantics of the current expression has some special things, such as side effects, asynchronicity, errors, indeterminism, multiplicity, and whatnot.</p><p>A full-blown algebraic effect system needs several components:</p><ul><li>A composition that aggregates all the effects on the go</li><li>A type system that behaves something like a semilattice</li><li>An effect handling that looks something like a &quot;Cut&quot; rule in logic</li></ul><p>The first one means that if we write something like <em>foo(bar(x))</em> or <em>foo(x) + bar(y)</em> where <em>foo </em>has effect <em>A</em> and <em>bar</em> has effect B, that whole operation should have an &#39;A + B&#39; effect. Where &#39;A&#39; and &#39;B&#39; can be anything from mutating some variables to parallel internode communication</p><p>A Second one means that you have some &quot;adding&quot; effects operation, commutative and idempotent. That is <em>a + b + a</em>, <em>a + b,</em> and <em>b + a</em> are all the same thing.</p><p>A third one means that you can sometimes take some expression with a complex effect like <em>a + b</em> and as soon as you have some &quot;handler&quot; for <em>b</em> you can apply that handler to your expression and get some new expression with only <em>a</em> mark on it.</p><p>Scala 3 had several possible mechanisms providing for such a system, notable two are:</p><ul><li>Contravariance</li><li>contextual abstraction</li></ul><p>Both are suggesting effects as capabilities. I.e., requiring an object of some type is the mark of effect, and providing a required object is handling.</p><p>The first one is based on the fact scala 3 already has a nice subtyping lattice. Meaning having some contravariant type Expr[-_] you can end up with the rule when composing expressions with Expr[A] and Expr[B] will lead you to some Expr[A &amp; B] with all the commutativity and idempotence for free. That was fully exploited by the first version of the ZIO module pattern.</p><p>However, &quot;handling&quot; was troublesome since it&#39;s not that easy to write a correct runtime that can &quot;subtract&quot; one trait from another, which eventually would lead you to the need of &quot;merging&quot; traits, i.e., providing a general function doing (A, B) =&gt; A &amp; B.</p><p>That was partially solved first by macros in the &quot;zio-macros&quot; library.</p><p>Then, a partial solution based on a TypeTag-keyed HashMap called Has arrived at ZIO. And ZIO-2 is going to make this hashmap completely hidden, leaving a user with types like <em>Console &amp; ReadUser &amp; Postgres</em>, where all of the <em>Console</em>, <em>ReadUser</em>, and <em>Postres</em> types are bare traits and not aliases to <em>Has</em>.</p><p>The second option, a contextual abstraction, was particularly interesting to M.Odersky. He felt that the mechanism of implicitly passing arguments during application is the best form of a capability-type of effect system. So having effects of <em>A</em> and <em>B</em> is easy as having contextual arguments of types <em>A</em> and <em>B</em>, i.e., having type <em>(A, B) ?=&gt; Whatever.</em></p><p>This mechanism has a straightforward effect handling - it&#39;s just an argument passing. However, it requires more direct typing effort from the user since contextual arguments can&#39;t be inferred yet.</p><p>Also it lacks basic properties since <em>(A, B) ?=&gt; X</em> is not the same type as <em>(B, A) ?=&gt; X</em> . And what is worse when <em>B</em> is a subtype of <em>A</em>, so <em>A ?=&gt; X</em> is a subtype of <em>B ?=&gt; X</em> for any <em>X</em> it&#39;s not true that <em>(A, B) ?=&gt; X</em> is the same as <em>B ?=&gt; X</em></p><p>But those weren&#39;t the issues that Martin was sad about. The most considerable trouble for him was a &quot;capability leaking&quot; problem. So imagine you have<em> </em><em>Database ?=&gt; User</em>. Technically you can provide some <em>Database</em> and now have a pure value of <em>User</em>, but there is no guarantee that some method or function inside the <em>User</em> hasn&#39;t captured this <em>Database</em> instance. So you continue your calculation, now free of <em>Database</em> formally and somewhere you start an SQL transaction all of sudden, using an old and maybe closed database session.</p><p>The dotty team was so obsessed with this misfortune that it reimplemented one of the most exciting things in rust type system: lifetimes.</p><h3>Lifetimes</h3><p>Imagine you have the compiler that builds an application with no garbage collection support and as small copying data as possible. So when you allocate something on the heap or the stack, you need to encourage to reuse this data, using some GC-untracked bare references to the object.</p><p>So rust introduced lifetime parameters.</p><p>Every function or type can have generic parameters like &#39;a &#39;b, these can be further applied to some reference or another generic entity and have meaning &quot;lower bound of how long this reference will leave&quot; or &quot;an interval where this reference is guaranteed to be correct.&quot;</p><p>So the following couple of definitions have drastically different semantics</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e79d6e83b6924e6b20dbc0f883eb6c6f/href">https://medium.com/media/e79d6e83b6924e6b20dbc0f883eb6c6f/href</a></iframe><p>If the return type doesn&#39;t mention the parameter&#39;s lifetime, the function probably performs something, access arguments during it, and constructs the result, totally independent of the argument.</p><p>The second means that the function probably uses the argument and puts it the result, so the result type will most likely be incorrect when the initially referenced value is moved or dropped.</p><h3>Capture checking</h3><p>The dotty team offers something similar in scala 3. But instead of presenting additional ephemerous types, it represents lifetimes with names of corresponding parameters. The first variant would look traditionally.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e619600cf5848b24b4592c2d9a281eef/href">https://medium.com/media/e619600cf5848b24b4592c2d9a281eef/href</a></iframe><p>And second, now have some exquisite mark on the type</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b5ffb485ee081a6c87cfc82ab3c9ee18/href">https://medium.com/media/b5ffb485ee081a6c87cfc82ab3c9ee18/href</a></iframe><p>So instead of adding the special named type marks, we can just use argument names as their &quot;lifetimes&quot;.</p><p>So why is this even relevant to a language with GC-enabled runtime such as scala?</p><p>First and most obvious, it solves the &quot;leaky capability&quot; problem. Now whenever <em>Database</em> is a trait marked with the <em>@capability</em> annotation, you can&#39;t write <em>Database ?=&gt; User</em> function unless the result is a <em>Database</em>-irrelevant value. Instead It should be something like</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b06f40b46226d5aa11cb9770fe7be13d/href">https://medium.com/media/b06f40b46226d5aa11cb9770fe7be13d/href</a></iframe><p>So you must somewhere explicitly mark that a result type isn&#39;t free of <em>db</em>. Does this enable contextual abstractions as a good effect system? It&#39;s hard to answer this, but I think it does a much more interesting thing.</p><p>One should be aware that capture checking does not involve &quot;linearity&quot; or another form of substructural typing. If we check carefully, none of the three most common structural rules (weakening, contraction, exchange) is compromised. The most tricky one, &quot;contraction,&quot; which provides &quot;reuse&quot; ability, is still safe. Although conclusion types can explicitly refer to a context variable&#39;s names, so does the dependent type system, and corresponding logic is not substructural. We can just &quot;reassign&quot; several names to a single variable during contraction.</p><h3>Resource scopes</h3><p>A typical resource-aware concurrent application in cats-effect or ZIO uses <em>Resource</em> or <em>ZManaged</em> monadic type. This type is usually based on some underlying asynchronous monad, say<em> </em><em>F[_]</em>, or <em>ZIO</em>, and includes:</p><ul><li>a step to initialize resource</li><li>a step to release the resource.</li></ul><p>So typical usage of such type would be <em>resource.use(actions)</em>, which is roughly equivalent to</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/58eff3629a9efbdd8c7af46fba577d52/href">https://medium.com/media/58eff3629a9efbdd8c7af46fba577d52/href</a></iframe><p>You resource can be compound, you can have several resource allocating procedures and have something like</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/4ce6fea6222fc26f06efd0692c81e989/href">https://medium.com/media/4ce6fea6222fc26f06efd0692c81e989/href</a></iframe><p>When you write something like <em>resource.use(actions) </em>whole sequence will look like</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8f2bf593cb27f86a7f5545d4f42e3236/href">https://medium.com/media/8f2bf593cb27f86a7f5545d4f42e3236/href</a></iframe><p>Resources have something like a statically known lifetime. Resource <em>c</em> lives from line 4 to 6, <em>b</em> lives from 3 to 7, and <em>a</em> from 2 to 8.</p><p>What if we need something like</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3dc418d709243c751f9f7b72c2d93080/href">https://medium.com/media/3dc418d709243c751f9f7b72c2d93080/href</a></iframe><p>In this code, we assume that <em>resB</em> and <em>resC</em> only use the <em>resA</em> result during initialization but don&#39;t need this during its life so that any function <em>g</em> can reference them without fear. But it seems that flows like that are difficult to express using the current form of static-scoped resource.</p><h3>RAII</h3><p>One of the nicest things about lifetimes in rust is that it helps to deal with the resources efficiently.</p><p>A code above can be translated to something like</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f099ec15c356fcd174ddec4e8b7247c2/href">https://medium.com/media/f099ec15c356fcd174ddec4e8b7247c2/href</a></iframe><p>The first thing we can see here - there is no actual need for deallocators, even <em>drop(a)</em> is optional since rust can automatically calculate drop time for each variable.</p><p>The second one: although <em>a</em> is dropped, we can freely use <em>b</em> and <em>c</em> since their lifetimes are supposedly not bound to <em>a</em>&#39;s.</p><p>The third is that we don&#39;t have a &quot;resource&quot; type here. Every construction can serve as a resource allocation.</p><p>Unfortunately, these niceties are hard to use in the concurrent code. Most popular rust implementations of asynchronicity use a global loop to schedule tasks. Each <em>Task</em> element is a special case of <em>Future</em> and must have a <em>&#39;static</em> lifetime to be scheduled. That means variables allocated in one task can’t be used as “lifetime tracked” resources in another. So if your &quot;resource&quot; should be used concurrently, it is tough to track its &quot;lifetime.&quot;</p><h3>Capture Checking And RAII</h3><p>In the new proposal, one can achieve something similar. You can distinguish between three types of usage, such as</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f5c5c8ef8be4f5538996b922bd72adf6/href">https://medium.com/media/f5c5c8ef8be4f5538996b922bd72adf6/href</a></iframe><p>The capture annotation before the IO means you can refer <em>{a}</em> during the calculation process. On the other hand, the annotation before <em>B</em> types reflects that the calculation result will still refer to the argument somehow.</p><p>That also means that technically we can have something like a resource without the need for different monadic types. Yet we must add some kind of mark on natural &quot;resources&quot;, things that need deallocation.</p><p>Say the standard calculation will have the type IO[normal, A] and resource-like IO[resource, A], we should adapt our flatMap accordingly. I.e.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/baf913c118b46755ddf261d206ac8924/href">https://medium.com/media/baf913c118b46755ddf261d206ac8924/href</a></iframe><p>That also means we need some more sophisticated for-comprehension (or other sugar) that could terminate flatMaps before the whole expression stops, so that:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0fb594b9c492641b9cc61ede05bd4cb7/href">https://medium.com/media/0fb594b9c492641b9cc61ede05bd4cb7/href</a></iframe><p>could be translated to</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b0364cd9d963d1ea27abd4606ae47c99/href">https://medium.com/media/b0364cd9d963d1ea27abd4606ae47c99/href</a></iframe><p>Note the left-associated flatMap on <em>resA</em> to close the resource preliminary based on the fact that <em>b</em> and <em>c</em> are not capturing <em>a</em> reference.</p><p>We can also add <em>drop(a)</em> here to enforce the correct end of life.</p><p>These `<em>normal</em>` and `<em>resource</em>` flags most probably can be thrown out using some additional &quot;capture&quot; annotation such as <em>(r: Release) ?-&gt; {r} Async[A]</em> can be an alias for<em> </em><em>IO[normal, A] </em>and <em>(r: Release) ?-&gt; {r} Async[ {r} A]</em> will be an alias for <em>IO[resource, A]</em>- a calculation that need some closing job.</p><p>So instead of having a particular monad for resources, we can have a scope mark representing scoped operations.</p><h3>Final thoughts</h3><p>Resource allocation is just one of the examples of how one can use the new capture checking mechanics.</p><p>But it&#39;s not the end of the story. In short - I don&#39;t think that capture checking is about effect tracking. I believe it&#39;s a beautiful tool for scope tracking.</p><p>There are much more scope-enabled concurrent problems such as</p><ul><li>Concurrent Locks</li><li>Database sessions</li><li>User HTTP sessions</li><li>STM</li></ul><p>Every time we have some auxiliary monadic type translated to IO, we introduce a special scoping, and scopes&#39; interoperations are tricky.</p><p>Capture checking adds an ability to have scope intersections and replace every narrow-purpose scope-marking type with a single lexical &quot;capability.&quot;</p><p>It enables the &quot;intersection&quot; of scopes and possibly eliminates functor zoos in existing concurrent libraries.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e4aa9bc4b3d1" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Final Free Structures with Subtyping (Scala)]]></title>
            <link>https://medium.com/@odomontois/final-free-structures-with-subtyping-scala-aee0cf35cfc0?source=rss-fe18154433bd------2</link>
            <guid isPermaLink="false">https://medium.com/p/aee0cf35cfc0</guid>
            <category><![CDATA[free-structures]]></category>
            <category><![CDATA[functional-programming]]></category>
            <category><![CDATA[subtyping]]></category>
            <category><![CDATA[final-tagless]]></category>
            <category><![CDATA[adt]]></category>
            <dc:creator><![CDATA[Oleg Nizhnik]]></dc:creator>
            <pubDate>Mon, 03 Jun 2019 16:21:46 GMT</pubDate>
            <atom:updated>2019-06-03T16:21:46.671Z</atom:updated>
            <content:encoded><![CDATA[<h3>Recap</h3><p>In the previous post, we’ve discovered this beautiful structure</p><pre><strong>trait </strong>Capture[-F[_]] {<br>  <strong>def </strong>continue[A](k: F[A]): A<br>}</pre><p>If some functor representing the tagless continuation of some data is provided as F[_], Capture[F] would represent an initial form of such data.</p><p>Contravariance can help represent unions in terms of intersections and vice versa, using the duality.</p><pre>Capture[F] &amp; Capture[G] = Capture[F | G]<br>Capture[F] | Capture[G] = Capture[F &amp; G]</pre><p>Still, we haven’t touched most useful properties of tagless final encoding yet:</p><ol><li>The ability to represent recursive data definitions</li><li>The ability to represent HKT</li></ol><p>Let’s start with recursion</p><h3>Free Construction</h3><p>There are a lot of recursive data structures representing some <a href="https://en.wikipedia.org/wiki/Free_object">free constructions</a>.</p><p>The one everyone loves is List[A] which is a known form of <a href="https://en.wikipedia.org/wiki/Free_monoid">a free monoid</a>.</p><p>Other examples are:</p><ul><li>NonEmptyList[A] is a free semigroup for A</li><li>Option[A] is a free pointed set for A</li></ul><p>Let’s define corresponding definitions</p><pre><strong>trait </strong>PointedE[-A, B]   <strong>extends </strong>(A =&gt; B) { <strong>def </strong>empty: B }</pre><pre><strong>trait </strong>SemigroupE[-A, B] <strong>extends </strong>Semigroup[B] <strong>with </strong>(A =&gt; B)</pre><pre><strong>trait </strong>MonoidE[-A, B]    <strong>extends </strong>Monoid[B] <strong>with </strong>SemigroupE[A, B]    <strong>with </strong>PointedE[A, B]</pre><p>Each of those definitions includes some Algebra[B] paired with embedding A =&gt; B.</p><p>Having this definition of free structure</p><pre><strong>trait </strong>FreeStruct[Algebra[_], A]{<br>  <strong>def </strong>continue[B](embed: A =&gt; B, algebra: Algebra[B]): B<br>}</pre><p>We’re just merging two arguments into the single trait resulting in</p><pre><strong>trait </strong>FreeStruct[AlgE[_, _], A]{<br>  <strong>def </strong>continue[B](algebraAndEmbed: AlgE[A, B]): B<br>}</pre><p>This may be simplified as</p><pre><strong>type </strong>FreeStruct[AlgE[_, _], A] = Capture[AlgE[A, ?]]</pre><p>Having this form we can define the following</p><pre><strong>type </strong>FreeSemigroup[+A] = Capture[SemigroupE[A, ?]]<br><strong>type </strong>FreeMonoid[+A]    = Capture[MonoidE[A, ?]]<br><strong>type </strong>FreePointed[+A]   = Capture[PointedE[A, ?]]</pre><p>What’s so special about it?</p><p>If we require SemigroupE andMonoidE implementations to follow usual Monoidand Semigroup laws,</p><p>we can be sure that</p><ul><li>FreePointed[A] is isomorphic to Option[A]</li><li>FreeSemigroup[A] is isomorphic to NonEmptyList[A]</li><li>FreeMonoid[A] is isomorphic to List[A]</li></ul><p>Let’s start from the Option:</p><pre><strong>def </strong>fromOption[A](opt: Option[A]): FreePointed[A] =<br>  <strong>new </strong>Capture[PointedE[A, ?]] {<br>    <strong>def </strong>continue[B](k: PointedE[A, B]): B = <br>      opt.fold(k.empty)(k.apply)<br>  }</pre><pre><strong>def </strong>toOption[A](opt: FreePointed[A]): Option[A] =<br>  opt.continue(<strong>new </strong>PointedE[A, Option[A]] {<br>    <strong>def </strong>empty: Option[A]       = None<br>    <strong>def </strong>apply(a: A): Option[A] = Some(a)<br>  })</pre><p>Next, take the NonEmptyList:</p><pre><strong>def </strong>fromNel[A](nel: NonEmptyList[A]): FreeSemigroup[A] =<br>  <strong>new </strong>Capture[SemigroupE[A, ?]] {<br>    <strong>def </strong>continue[B](k: SemigroupE[A, B]): B =  <br>         nel.reduceMap(k.apply)(k)<br>  }</pre><pre><strong>def </strong>toNel[A](nel: FreeSemigroup[A]): NonEmptyList[A] =<br>  nel.continue(<strong>new </strong>SemigroupE[A, NonEmptyList[A]] {<br>    <strong>def </strong>apply(a: A): NonEmptyList[A]  = NonEmptyList.<em>one</em>(a)<br>    <strong>def </strong>combine(x: NonEmptyList[A], y: NonEmptyList[A]): NonEmptyList[A] = x ::: y<br>  })</pre><p>And finally the List</p><pre><strong>def </strong>fromList[A](l: List[A]): FreeMonoid[A] =<br>  <strong>new </strong>Capture[MonoidE[A, ?]] {<br>    <strong>def </strong>continue[B](k: MonoidE[A, B]): B = l.foldMap(k.apply)(k)<br>  }</pre><pre><strong>def </strong>toList[A](l: FreeMonoid[A]): List[A] =<br>  l.continue(<strong>new </strong>MonoidE[A, List[A]] {<br>    <strong>def </strong>apply(a: A): List[A]                     = <em>List</em>(a)<br>    <strong>def </strong>empty: List[A]                           = <em>Nil<br>    </em><strong>def </strong>combine(x: List[A], y: List[A]): List[A] = x ::: y<br>  })</pre><p>Now we can define some basic constructors</p><pre><strong>def </strong>single[A](a: A): Capture[A =&gt; ?] = <strong>new </strong>Capture[A =&gt; ?] {<br>  <strong>def </strong>continue[B](k: A =&gt; B): B = k(a)<br>}</pre><pre><strong>def </strong>combine[A, F[x] &lt;: SemigroupE[A, x]](<br>   xs: Capture[F], <br>   ys: Capture[F]): Capture[F] =<br>  <strong>new </strong>Capture[F] {<br>    <strong>def </strong>continue[B](k: F[B]): B = <br>       k.combine(xs.continue(k), ys.continue(k))<br>  }</pre><pre><strong>def </strong>empty[A, F[x] &lt;: PointedE[A, x]]: Capture[F] =<br>  <strong>new </strong>Capture[F] {<br>    <strong>def </strong>continue[B](k: F[B]): B = k.empty<br>  }</pre><p>The intriguing property of this representation is the ability to embed free constructions via subtyping</p><pre>FreeSemigroup[A] &lt;: FreeMonoid[A]<br>FreePointed[A] &lt;: FreeMonoid[A]</pre><p>Particularly we achieved</p><ol><li>NonEmptyList that is a subtype of List</li><li>Option that is a subtype of List</li><li>single that can create each of Option, List, and NonEmptyList without any type class magic</li><li>empty that can create both Lists and Options</li><li>combine that able to <br>- concatenate two NonEmptyLists resulting in NonEmptyList<br>- concatenate couple of Options, Option and NonEmptyList or a couple of Lists resulting in simple List</li></ol><p>So we now have a lot of data relations without special type classes, representing them.</p><h3>Definitions</h3><p>Before we continue, we need to make a few additional definitions</p><p>First is a <a href="https://github.com/snowleopard/selective">selective functor</a></p><p>This is just an extension of Applicativeallowing for conditional effect composition.</p><p>We define such as</p><pre><strong>trait </strong>Selective[F[_]] <strong>extends </strong>Applicative[F] {<br>  <strong>def </strong>select[A, B](fab: F[Either[A, B]], fa: =&gt; F[B]): F[B]<br>}</pre><p>The second one is just a redefinition of <a href="https://typelevel.org/cats/datatypes/functionk.html">FunctionK</a> having variance marks on type parameters</p><pre><strong>trait </strong>FunK[-F[_], +G[_]] {<br>  <strong>def </strong>apply[A](fa: F[A]): G[A]<br>}</pre><p>That gives us more subtyping when we apply functor embedding</p><h3>Higher Kinded Types</h3><p>Now it’s time to remind the Functor power hierarchy</p><pre>Functor       Pure<br>   |           |<br>   V           |<br>Applicative &lt;--+<br>   |<br>   V<br>Selective<br>   | <br>   V<br>Monad</pre><p>Each of these definitions could have a free form like <a href="https://typelevel.org/cats/datatypes/freemonad.html">Free Monad</a> or<a href="https://typelevel.org/cats/datatypes/freeapplicative.html"> Free Applicative</a></p><p>Unluckily we are forced to define each free ADT separately, copying common constructors, and translating between using folds</p><p>We can start from this upgrade of Capture</p><pre><strong>trait </strong>Capture1[-K[_[_]], A] {<br>  <strong>def </strong>continue[F[_]](k: K[F]): F[A]<br>}</pre><p>This is pretty much like the previous one, but continuation algebra is now higher kinded. We might represent functor capabilities using it.</p><p>We define our Embedding Algebras:</p><pre><strong>trait </strong>PureE[-F[_], G[_]]        <strong>extends </strong>FunK[F, G] <strong>with </strong>Pure[G]</pre><pre><strong>trait </strong>FunctorE[-F[_], G[_]]     <strong>extends </strong>FunK[F, G] <strong>with </strong>Functor[G]</pre><pre><strong>trait </strong>ApplicativeE[-F[_], G[_]] <strong>extends </strong>FunctorE[F, G] <br>                                <strong>with </strong>PureE[F, G] <br>                                <strong>with </strong>Applicative[G]</pre><pre><strong>trait </strong>SelectiveE[-F[_], G[_]]   <strong>extends </strong>ApplicativeE[F, G] <br>                                <strong>with </strong>Selective[G]</pre><pre><strong>trait </strong>MonadE[-F[_], G[_]]       <strong>extends </strong>Monad[G] <br>                                <strong>with </strong>SelectiveE[F, G] {<br>  <strong>def </strong>select[A, B](fab: G[Either[A, B]], fa: =&gt; G[B]): G[B] =<br>    flatMap(fab) {<br>      <strong>case </strong>Left(a)  =&gt; fa<br>      <strong>case </strong>Right(b) =&gt; pure(b)<br>    }<br>}</pre><p>And the collection of free functorial Structures</p><pre><strong>type </strong>FreeF[+F[_], A]           = Capture1[FunK[F, ?[_]], A]</pre><pre><strong>type </strong>FreeFunctor[+F[_], A]     = Capture1[FunctorE[F, ?[_]], A]</pre><pre><strong>type </strong>FreePure[+F[_], A]        = Capture1[PureE[F, ?[_]], A]</pre><pre><strong>type </strong>FreeApplicative[+F[_], A] = <br>     Capture1[ApplicativeE[F, ?[_]], A]</pre><pre><strong>type </strong>FreeSelective[+F[_], A]   = Capture1[SelectiveE[F, ?[_]], A]</pre><pre><strong>type </strong>FreeMonad[+F[_], A]       = Capture1[MonadE[F, ?[_]], A]</pre><p>Now we’ll start defining our instances. First one is Pure</p><pre><strong>trait </strong>PureInstance[F[_], K[g[_]] &lt;: PureE[F, g]] <br>   <strong>extends </strong>Pure[Capture1[K, ?]] {<br>  <strong>override def </strong>pure[A](x: A) = <strong>new </strong>Capture1[K, A] {<br>    <strong>def </strong>continue[G[_]](k: K[G]): G[A] = k.pure(x)<br>  }<br>}</pre><pre><strong>implicit def </strong>pure[F[_]]: Pure[FreePure[F, ?]] = <br>    <strong>new </strong>PureInstance[F, PureE[F, ?[_]]]       {}</pre><p>Next one is Functor</p><pre><strong>trait </strong>FunctorInstance[F[_], K[g[_]] &lt;: FunctorE[F, g]] <br>   <strong>extends </strong>Functor[Capture1[K, ?]] {<br>  <strong>override def </strong>map[A, B](fa: Capture1[K, A])(f: A =&gt; B) =<br>    <strong>new </strong>Capture1[K, B] {<br>      <strong>def </strong>continue[G[_]](k: K[G]): G[B] = k.map(fa.continue(k))(f)<br>    }<br>}</pre><pre><strong>implicit def </strong>functor[F[_]]: Functor[FreeFunctor[F, ?]] = <br>   <strong>new </strong>FunctorInstance[F, FunctorE[F, ?[_]]] {}</pre><p>Why do we have some strange type parameter like</p><p>K[g[_]] &lt;: PureE[F, g]</p><p>or K[g[_]] &lt;: FunctorE[F, g] ?</p><p>It allows us to reuse our instance implementation to implement more powerful instances, let’s continue with Applicative</p><pre><strong>trait </strong>ApplicativeInstance[F[_], K[g[_]] &lt;: ApplicativeE[F, g]]<br>    <strong>extends </strong>Applicative[Capture1[K, ?]] <br>    <strong>with </strong>FunctorInstance[F, K] <br>    <strong>with </strong>PureInstance[F, K] {<br><br>  <strong>override def </strong>ap[A, B]<br>    (ff: Capture1[K, A =&gt; B])<br>     (fa: Capture1[K, A]) =<br>    <strong>new </strong>Capture1[K, B] {<br>      <strong>def </strong>continue[G[_]](k: K[G]): G[B] = <br>        k.ap(ff.continue(k))(fa.continue(k))<br>    }<br>}</pre><pre><strong>implicit def </strong>applicative[F[_]]: Applicative[FreeApplicative[F, ?]] = <strong>new </strong>ApplicativeInstance[F, ApplicativeE[F, ?[_]]] {}</pre><p>Then Selective</p><pre><strong>trait </strong>SelectiveInstance[F[_], K[g[_]] &lt;: SelectiveE[F, g]]<br>    <strong>extends </strong>Selective[Capture1[K, ?]] <br>    <strong>with </strong>ApplicativeInstance[F, K] {<br>  <strong>def </strong>select[A, B]<br>  (fab: Capture1[K, Either[A, B]], <br>   fa: =&gt; Capture1[K, B]) =<br>    <strong>new </strong>Capture1[K, B] {<br>      <strong>def </strong>continue[G[_]](k: K[G]): G[B] =   <br>        k.select(fab.continue(k), fa.continue(k))<br>    }<br>}<br><strong>implicit def </strong>selective[F[_]]: Selective[FreeSelective[F, ?]] = <br>   <strong>new </strong>SelectiveInstance[F, SelectiveE[F, ?[_]]] {}</pre><p>And finally her highness Monad</p><pre><strong>trait </strong>MonadInstance[F[_], K[g[_]] &lt;: MonadE[F, g]]<br>    <strong>extends </strong>StackSafeMonad[Capture1[K, ?]] <br>    <strong>with </strong>SelectiveInstance[F, K] {<br>  <strong>def </strong>flatMap[A, B]<br>    (fa: Capture1[K, A])<br>    (f: A =&gt; Capture1[K, B]) =<br>    <strong>new </strong>Capture1[K, B] {<br>      <strong>def </strong>continue[G[_]](k: K[G]): G[B] = <br>        k.flatMap(fa.continue(k))(a =&gt; f(a).continue(k))<br>    }<br>}<br><strong>implicit def </strong>monad[F[_]]: Monad[FreeMonad[F, ?]]             = <br>   <strong>new </strong>MonadInstance[F, MonadE[F, ?[_]]]         {}</pre><p>The most useful constructor: embedding of any HKT application within any free structure</p><pre><strong>def </strong>embed[F[_], A](fa: F[A]): FreeF[F, A] =<br>  <strong>new </strong>FreeF[F, A] {<br>    <strong>def </strong>continue[G[_]](k: FunK[F, G]): G[A] = k(fa)<br>  }</pre><p>We define simple isomorphism with cats.free.Free to show we didn’t lose any power</p><pre><strong>def </strong>fromFreeMonad[F[_], A](fa: cats.free.Free[F, A]): <br>   FreeMonad[F, A] =<br>  fa.foldMap[FreeMonad[F, ?]](<em>functionK</em>[F](fa =&gt; <em>embed</em>(fa)))<br><br><strong>def </strong>toFreeMonad[F[_], X](fa: FreeMonad[F, X]): Free[F, X] =<br>  fa.continue(<br>   <strong>new </strong>MonadE[F, Free[F, ?]] <strong>with </strong>StackSafeMonad[Free[F, ?]] {<br>    <strong>def </strong>pure[A](a: A): Free[F, A] = <br>       Free.<em>pure</em>(a)<br>    <strong>def </strong>apply[A](fa: F[A]): Free[F, A] = <br>       Free.<em>liftF</em>(fa)<br>    <strong>def </strong>flatMap[A, B](fa: Free[F, A])<br>                     (f: A =&gt; Free[F, B]): Free[F, B]   =  <br>       fa.flatMap(f)<br>  })</pre><p>One can easily verify that</p><p>FreeApplicative[F] &lt;: FreeMonad[F]</p><p>and also for each F[_] &lt;: G[_]</p><p>FreeMonad[F] &lt;: FreeMonad[G]</p><p>That property can be extremely useful since we might use</p><p>FreeMonad[Console | UserStore | Authorization, ?]</p><p>instead of nasty InjectKs like</p><pre>[F[_]<br>  : Console :&lt;: ?[_] <br>  : UserStore :&lt;: ?[_] <br>  : Authorization :&lt;: ?[_] ]  Free[F]</pre><p>And have Free monads with nice type inference and seamless embedding</p><p>Also, we can express more powerful types like FreeIO monad with precise effect control and effect system, powered by subtyping, pretty much like <a href="https://zio.dev/">ZIO</a> but allowing to embed any functor and control async/concurrency capabilities, but this is a theme for the following posts.</p><h3>Conclusion</h3><p>Final algebraic form along with contravariance gives a chance to build powerful cost-free relation system between recursive types, simple or higher-kinded.</p><p>We can redefine some well-known structures as free definitions, gaining two-dimensional subtyping control:</p><ul><li>Covariance on base set (alphabet)</li><li>Contravariance on algebra structure</li></ul><p>Latter means that more restrictive (based on weaker algebras) data structures are subtypes for less restrictive. NonEmptyLists and Options are subtypes of Lists, and FreeApplicatives and FreeSelectives are subtypes of FreeMonads</p><h3>Code</h3><p>All the code samples presented in this package</p><p><a href="https://github.com/manatki/manatki/tree/master/src/main/scala/manatki/free">manatki/manatki</a></p><h4>Thanks</h4><p>Special thanks to <a href="https://twitter.com/katzenstrophe">https://twitter.com/katzenstrophe</a> for the help in preparing this post.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=aee0cf35cfc0" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Tagless unions in  scala 2.12]]></title>
            <link>https://medium.com/@odomontois/tagless-unions-in-scala-2-12-55ab0100c2ff?source=rss-fe18154433bd------2</link>
            <guid isPermaLink="false">https://medium.com/p/55ab0100c2ff</guid>
            <category><![CDATA[union-types]]></category>
            <category><![CDATA[zio]]></category>
            <category><![CDATA[final-tagless]]></category>
            <category><![CDATA[scala]]></category>
            <dc:creator><![CDATA[Oleg Nizhnik]]></dc:creator>
            <pubDate>Fri, 17 May 2019 12:39:16 GMT</pubDate>
            <atom:updated>2019-05-17T14:57:04.459Z</atom:updated>
            <content:encoded><![CDATA[<h3>Tagless unions in scala 2.12</h3><p>So you’ve found yourself again in this situation.<br>You have 2+ error ADTs like this</p><pre><strong>sealed trait </strong>PasswordError<br><br><strong>object </strong>PasswordError{<br>  <strong>case class </strong>TooShort(required: Int) <strong>extends </strong>PasswordError<br>  <strong>case class </strong>ToesNotContain(chars: String) <strong>extends </strong>PasswordError<br>}</pre><p>And this</p><pre><strong>sealed trait </strong>LoginError<br><br><strong>object </strong>LoginError{<br>  <strong>case class </strong>TooLong(maxLength: Int) <strong>extends </strong>LoginError<br>  <strong>case object </strong>BadFormat <strong>extends </strong>LoginError<br>}</pre><p>Next, you use some monadic type, using checked errors like <br>Either or ZIO, and have some of the code like having different checked errors</p><pre><strong>def </strong>validateLogin(login: String): ZIO[HasLoginConfig, LoginError, Unit]</pre><pre><strong>def </strong>validatePassword(pass: String): ZIO[HasPasswordConfig, PasswordError, Unit]</pre><p>And you’d like to use both of them in the single expression, so that result type can express the possibility of either error</p><pre><strong>def </strong>validateUser(user: User) = <br>  <em>validateLogin</em>(user.login) *&gt; <em>validatePassword</em>(user.pass)</pre><p>Good news: your error type parameter has “covariant” tag so you can expect something like</p><pre>ZIO[<br>  HasLoginConfig &amp; HasPasswordConfig, <br>  LoginError | PasswordError<br>, Unit]</pre><p>Bad news: scala 2 still has not any type union operation, yet it has the with operator: not-always-commutative type intersection</p><p>If you aren’t familiar with <a href="http://okmij.org/ftp/tagless-final/course/lecture.pdf">tagless final approach</a> yet it’s about time. There is plenty of videos like that one, just google it</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2Fq6JCvdMWtmo%3Ffeature%3Doembed&amp;url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3Dq6JCvdMWtmo&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2Fq6JCvdMWtmo%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/e2ade93f2fd29e4dbe187783a7cb00c7/href">https://medium.com/media/e2ade93f2fd29e4dbe187783a7cb00c7/href</a></iframe><p>So start from redefining your error ADT’s as single parameter traits like</p><pre><strong>trait </strong>LoginErr[+A] {<br>  <strong>def </strong>tooLong(maxLength: Int): A<br>  <strong>def </strong>badFormat: A<br>}</pre><pre><strong>trait </strong>PasswordErr[+A] {<br>  <strong>def </strong>tooShort(required: Int): A<br>  <strong>def </strong>doesNotContain(chars: String): A<br>}</pre><p>Starting from here, LoginErr[A] is equivalent to LoginError =&gt; A it’s just little bit more effective.</p><p>If you had pattern matching like</p><pre>{<br>  case TooLong(x) =&gt; a<br>  case BadFormat =&gt; b<br>}</pre><p>you may just replace it with</p><pre><strong>new </strong>LoginErr[X] {<br>  <strong>def </strong>tooLong(x: Int) = a<br>  <strong>def </strong>badFormat = b<br>}</pre><p>And we have exhaustiveness check for free</p><p>But what should we match? We might need some “initial” form of our algebra, let’s introduce the universal <strong>initializer</strong></p><pre><strong>trait </strong>Capture[-F[_]] {<br>  <strong>def </strong>continue[A](k: F[A]): A<br>}</pre><p>Here F is the placeholder for your algebra, e.g. LoginErr or PasswordErr</p><p>To apply the “pattern matching” you need just pass your LoginErr[X] to the continue method and get back your X result</p><p>Why have we marked our -F[_] as contravariant? This is the main part</p><p>So our capture is just a natural (hopefully) transformation F ~&gt; Id with covariance on the argument functor</p><p>Recalling that we are going to use some “algebras” as F it’s just a<br>[A] (ADT =&gt; A) =&gt; A where [A] f[A] is just a fancy syntax for higher-ranked type, forall a. f a if you prefer</p><p>According to Yoneda lemma[A] (ADT =&gt; A) =&gt; A is moral equivalent to ADT, you can verify just applying Yoneda to Scala wannabe-category and Id endofunctor, that means that Capture[LoginErr] is same as LoginError from our first attempt</p><p>Next, we might play a little bit with variances, if C[+A] is covariant you’ll have</p><pre>C[A] &amp; C[B] = C[A &amp; B]<br>C[A] | C[B] = C[A | B]</pre><p>Сonversely if C[-A] is contravariant you’ll have</p><pre>C[A] &amp; C[B] = C[A | B]<br>C[A] | C[B] = C[A &amp; B]</pre><p>Scala might not have | and &amp; operations on type level, but those rules are effective when scalac is searching for least upper and greatest lower bounds during the type inference.</p><p>Recalling that functions -A =&gt; +B are covariant on the result and contravariant on the parameter we may conclude that</p><pre>PasswordErr[A] &amp; LoginErr[A] ~<br>(PasswordError =&gt; A) &amp; (LoginError =&gt; A) =<br>(PasswordError | LoginError) =&gt; A</pre><p>So PasswordErr[A] with LoginErr[A] is a special type that is effectively algebra corresponding to some union ADT PasswordError | LoginError</p><p>And that’s great because when compiler search for the least upper bound of</p><p>Capture[PasswordErr] and Capture[LoginError]</p><p>it should find</p><p>Capture[[A] PasswordErr[A] with LoginErr[A]]</p><p>due to Capture contravariance which is moral equivalent to union PasswordError | LoginError. And to “pattern match” it you need to implement merged PasswordErr with LoginErr , that will require you to implement all four methods, that is pattern match all four possible constructors</p><p>Now it’s time for some boilerplate.</p><p>For the real use, we’ll need easy Capture construction, without hesitation, we use <a href="https://github.com/alexknvl">Alex Konovalov</a>’s trick for higher-ranked lambdas</p><pre><strong>object </strong>Capture {<br>  <strong>type </strong>Arbitrary<br><br>  <strong>def </strong>apply[F[_]] = <strong>new </strong>Apply[F]<br><br>  <strong>class </strong>Apply[F[_]] {<br>    <strong>def </strong>apply(f: F[Arbitrary] =&gt; Arbitrary): Capture[F] = <br>    <strong>new </strong>Capture[F] {<br>      <strong>def </strong>continue[A](k: F[A]): A = <br>         f(k.asInstanceOf[F[Arbitrary]]).asInstanceOf[A]<br>    }<br>  }<br>}</pre><p>Now we can implement the <em>initial algebra, </em>that is — implementation of our algebra trait for the initial Capture type</p><pre><strong>object </strong>LoginErr <strong>extends </strong>LoginErr[Capture[LoginErr]] {<br>  <strong>def </strong>tooLong(maxLength: Int) =  <br>      <em>Capture</em>[LoginErr](_.tooLong(maxLength))<br>  <strong>val </strong><em>badFormat               </em>= <br>      <em>Capture</em>[LoginErr](_.badFormat)<br>}</pre><p>this methods could be used as constructor, we can simplify types defining</p><pre><strong>type </strong>Constructors[F[_]] = F[Capture[F]]</pre><p>The full code can be found in this repo <a href="https://github.com/Odomontois/zio-tagless-err">https://github.com/Odomontois/zio-tagless-err</a></p><p>Special thanks to <a href="https://t.me/scala_ponv">https://t.me/scala_ponv</a> community for the forcing to write my debut blog post</p><p>Any remarks, corrections, including English grammar are appreciated</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=55ab0100c2ff" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>