{"id":777,"date":"2018-06-27T06:22:53","date_gmt":"2018-06-27T05:22:53","guid":{"rendered":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/?p=777"},"modified":"2019-08-18T21:50:00","modified_gmt":"2019-08-18T20:50:00","slug":"selective","status":"publish","type":"post","link":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/selective\/","title":{"rendered":"Selective applicative functors"},"content":{"rendered":"<p><strong>Update:<\/strong> I have written a paper about selective applicative functors, and it completely supersedes this blog post (it also uses a slightly different notation). You should <a href=\"https:\/\/dl.acm.org\/ft_gateway.cfm?id=3341694\">read the paper instead<\/a>.<\/p>\n<p>I often need a Haskell abstraction that supports conditions (like <span style=\"color: #000080\">Monad<\/span>) yet can still be statically analysed (<a href=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/the-task-abstraction\/\">like Applicative<\/a>). In such cases people typically point to the <span style=\"color: #000080\">Arrow<\/span> class, more specifically <span style=\"color: #000080\">ArrowChoice<\/span>, but <a href=\"https:\/\/en.wikibooks.org\/wiki\/Haskell\/Understanding_arrows\">when I look it up<\/a>, I find several type classes and a dozen of methods. Impressive, categorical but also quite heavy. Is there a more lightweight approach?\u00a0In this blog post I&#8217;ll explore what I call <em>selective applicative functors<\/em>, which extend the <span style=\"color: #000080\">Applicative<\/span> type class with a single method that makes it possible to be selective about effects.<\/p>\n<p>Please meet <span style=\"color: #000080\">Selective<\/span>:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #794938\">class<\/span> <span style=\"color: #bf4f24\">Applicative<\/span> <span style=\"color: #234a97\">f<\/span> =&gt; <span style=\"color: #bf4f24\">Selective<\/span> <span style=\"color: #234a97\">f<\/span> <span style=\"color: #794938\">where<\/span>\r\n    <span style=\"color: #bf4f24\">handle<\/span> <span style=\"color: #794938\">::<\/span> <span style=\"color: #234a97\">f<\/span> (<span style=\"color: #691c97\">Either<\/span> <span style=\"color: #234a97\">a<\/span> <span style=\"color: #234a97\">b<\/span>) <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #234a97\">f<\/span> (<span style=\"color: #234a97\">a<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #234a97\">b<\/span>) <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #234a97\">f<\/span> <span style=\"color: #234a97\">b<\/span>\r\n<\/pre>\n<p>Think of <span style=\"color: #000080\">handle<\/span> as a\u00a0<em>selective function application<\/em>: you apply a handler function of type <span style=\"color: #000080\">a\u00a0\u2192\u00a0b<\/span> when given a value of type <span style=\"color: #000080\">Left a<\/span>, but can skip the handler (along with its effects) in the case of <span style=\"color: #000080\">Right b<\/span>. Intuitively, <span style=\"color: #000080\">handle<\/span> allows you to\u00a0<em>efficiently<\/em>\u00a0handle errors, i.e. perform the error-handling effects only when needed.<\/p>\n<p><!--more--><\/p>\n<p>Note that you can write a function with this type signature using <span style=\"color: #000080\">Applicative<\/span> functors, but it will always execute the effect associated with the handler so it&#8217;s potentially less efficient:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #bf4f24\">handleA<\/span> <span style=\"color: #794938\">::<\/span> <span style=\"color: #a71d5d;font-style: italic\">Applicative<\/span> <span style=\"color: #234a97\">f<\/span> <span style=\"color: #794938\">=&gt;<\/span> <span style=\"color: #234a97\">f<\/span> (<span style=\"color: #691c97\">Either<\/span> <span style=\"color: #234a97\">a<\/span> <span style=\"color: #234a97\">b<\/span>) <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #234a97\">f<\/span> (<span style=\"color: #234a97\">a<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #234a97\">b<\/span>) <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #234a97\">f<\/span> <span style=\"color: #234a97\">b<\/span>\r\nhandleA x f <span style=\"color: #794938\">=<\/span> (<span style=\"color: #794938\">\\<\/span>e f <span style=\"color: #794938\">-&gt;<\/span> either f <span style=\"color: #693a17\">id<\/span> e) <span style=\"color: #794938\">&lt;$&gt;<\/span> x <span style=\"color: #794938\">&lt;<\/span>*<span style=\"color: #794938\">&gt;<\/span> f\r\n<\/pre>\n<p><span style=\"color: #000080\">Selective<\/span> is more powerful<span style=\"color: #000080\"><sup>(*)<\/sup><\/span> than <span style=\"color: #000080\">Applicative<\/span>:\u00a0you can recover the application operator <span style=\"color: #000080\">&lt;*&gt;<\/span> as follows (I&#8217;ll use the suffix <span style=\"color: #000080\">S<\/span> for <span style=\"color: #000080\">Selective<\/span>).<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #bf4f24\">apS<\/span> <span style=\"color: #794938\">::<\/span> <span style=\"color: #a71d5d;font-style: italic\">Selective<\/span> <span style=\"color: #234a97\">f<\/span> <span style=\"color: #794938\">=&gt;<\/span> <span style=\"color: #234a97\">f<\/span> (<span style=\"color: #234a97\">a<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #234a97\">b<\/span>) <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #234a97\">f<\/span> <span style=\"color: #234a97\">a<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #234a97\">f<\/span> <span style=\"color: #234a97\">b<\/span>\r\napS f x <span style=\"color: #794938\">=<\/span> handle (<span style=\"color: #b4371f\">Left<\/span> <span style=\"color: #794938\">&lt;$&gt;<\/span> f) (<span style=\"color: #693a17\">flip<\/span> <span style=\"color: #bf4f24\">($)<\/span> <span style=\"color: #794938\">&lt;$&gt;<\/span> x)\r\n<\/pre>\n<p>Here we tag a given function <span style=\"color: #000080\">a \u2192 b<\/span> as an error and turn a value of type\u00a0<span style=\"color: #000080\">a<\/span> into an error-handling function <span style=\"color: #000080\">($a)<\/span>, which simply applies itself to the error <span style=\"color: #000080\">a \u2192 b<\/span> yielding <span style=\"color: #000080\">b<\/span> as desired. We will later define laws for the <span style=\"color: #000080\">Selective<\/span> type class which will ensure that <span style=\"color: #000080\">apS<\/span> is a legal application operator <span style=\"color: #000080\">&lt;*&gt;<\/span>, i.e. that it satisfies the laws of the <span style=\"color: #000080\">Applicative<\/span> type class.<\/p>\n<p>The <span style=\"color: #000080\">select<\/span> function is a natural generalisation of <span style=\"color: #000080\">handle<\/span>: instead of skipping one unnecessary effect, it selects which of the two given effectful functions to apply to a given value. It is possible to implement <span style=\"color: #000080\">select<\/span> in terms of <span style=\"color: #000080\">handle<\/span>, which is a good puzzle (try it!):<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #bf4f24\">select<\/span> <span style=\"color: #794938\">::<\/span> <span style=\"color: #a71d5d;font-style: italic\">Selective<\/span> <span style=\"color: #234a97\">f<\/span> <span style=\"color: #794938\">=&gt;<\/span>\r\n    f (<span style=\"color: #811f24;font-weight: bold\">Either<\/span> a b) <span style=\"color: #794938\">-&gt;<\/span> f (a <span style=\"color: #794938\">-&gt;<\/span> c) <span style=\"color: #794938\">-&gt;<\/span> f (b <span style=\"color: #794938\">-&gt;<\/span> c) <span style=\"color: #794938\">-&gt;<\/span> f c\r\nselect <span style=\"color: #794938\">=<\/span> <span style=\"color: #794938\">...<\/span> <span style=\"color: #5a525f;font-style: italic\">-- Try to figure out the implementation!<\/span>\r\n<\/pre>\n<p>Finally, any <span style=\"color: #000080\">Monad<\/span> is <span style=\"color: #000080\">Selective<\/span>:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #bf4f24\">handleM<\/span> <span style=\"color: #794938\">::<\/span> <span style=\"color: #a71d5d;font-style: italic\">Monad<\/span> <span style=\"color: #234a97\">f<\/span> <span style=\"color: #794938\">=&gt;<\/span> <span style=\"color: #234a97\">f<\/span> (<span style=\"color: #691c97\">Either<\/span> <span style=\"color: #234a97\">a<\/span> <span style=\"color: #234a97\">b<\/span>) <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #234a97\">f<\/span> (<span style=\"color: #234a97\">a<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #234a97\">b<\/span>) <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #234a97\">f<\/span> <span style=\"color: #234a97\">b<\/span>\r\nhandleM mx mf <span style=\"color: #794938\">=<\/span> <span style=\"color: #794938\">do<\/span>\r\n    x <span style=\"color: #794938\">&lt;-<\/span> mx\r\n    <span style=\"color: #794938\">case<\/span> x <span style=\"color: #794938\">of<\/span>\r\n        <span style=\"color: #b4371f\">Left<\/span>  a <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #693a17\">fmap<\/span> (<span style=\"color: #794938\">$<\/span>a) mf\r\n        <span style=\"color: #b4371f\">Right<\/span> b <span style=\"color: #794938\">-&gt;<\/span> pure b\r\n<\/pre>\n<p>Selective functors are sufficient for implementing many conditional constructs, which traditionally require the (more powerful) <span style=\"color: #000080\">Monad<\/span> type class. For example:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #bf4f24\">ifS<\/span> <span style=\"color: #794938\">::<\/span> <span style=\"color: #a71d5d;font-style: italic\">Selective<\/span> <span style=\"color: #234a97\">f<\/span> <span style=\"color: #794938\">=&gt;<\/span> <span style=\"color: #234a97\">f<\/span> <span style=\"color: #691c97\">Bool<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #234a97\">f<\/span> <span style=\"color: #234a97\">a<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #234a97\">f<\/span> <span style=\"color: #234a97\">a<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #234a97\">f<\/span> <span style=\"color: #234a97\">a<\/span>\r\nifS i t e <span style=\"color: #794938\">=<\/span> select\r\n    (bool (<span style=\"color: #b4371f\">Right<\/span> <span style=\"color: #811f24;font-weight: bold\">()<\/span>) (<span style=\"color: #b4371f\">Left<\/span> <span style=\"color: #811f24;font-weight: bold\">()<\/span>) <span style=\"color: #794938\">&lt;$&gt;<\/span> i) (<span style=\"color: #693a17\">const<\/span> <span style=\"color: #794938\">&lt;$&gt;<\/span> t) (<span style=\"color: #693a17\">const<\/span> <span style=\"color: #794938\">&lt;$&gt;<\/span> e)\r\n<\/pre>\n<p>Here we turn a Boolean value into <span style=\"color: #000080\">Left ()<\/span> or <span style=\"color: #000080\">Right ()<\/span> and then <span style=\"color: #000080\">select<\/span> an appropriate branch. Let&#8217;s try this function in a GHCi session:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\">\u03bb<span style=\"color: #794938\">&gt;<\/span> ifS (<span style=\"color: #693a17\">odd<\/span> <span style=\"color: #794938\">.<\/span> <span style=\"color: #693a17\">read<\/span> <span style=\"color: #794938\">&lt;$&gt;<\/span> <span style=\"color: #693a17\">getLine<\/span>) (<span style=\"color: #693a17\">putStrLn<\/span> <span style=\"color: #0b6125\">\"Odd\"<\/span>) (<span style=\"color: #693a17\">putStrLn<\/span> <span style=\"color: #0b6125\">\"Even\"<\/span>)\r\n<span style=\"color: #811f24;font-weight: bold\">0<\/span>\r\n<span style=\"color: #811f24;font-weight: bold\">Even<\/span>\r\n\r\n\u03bb<span style=\"color: #794938\">&gt;<\/span> ifS (<span style=\"color: #693a17\">odd<\/span> <span style=\"color: #794938\">.<\/span> <span style=\"color: #693a17\">read<\/span> <span style=\"color: #794938\">&lt;$&gt;<\/span> <span style=\"color: #693a17\">getLine<\/span>) (<span style=\"color: #693a17\">putStrLn<\/span> <span style=\"color: #0b6125\">\"Odd\"<\/span>) (<span style=\"color: #693a17\">putStrLn<\/span> <span style=\"color: #0b6125\">\"Even\"<\/span>)\r\n<span style=\"color: #811f24;font-weight: bold\">1<\/span>\r\n<span style=\"color: #811f24;font-weight: bold\">Odd<\/span>\r\n<\/pre>\n<p>As desired, only one of the two effectful functions is executed. Note that here <span style=\"color: #000080\">f = IO<\/span> with the default selective instance: <span style=\"color: #000080\">handle = handleM<\/span>.<\/p>\n<p>Using <span style=\"color: #000080\">ifS<\/span> as a building block, we can implement other useful functions:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #5a525f;font-style: italic\">-- | Conditionally apply an effect.<\/span>\r\n<span style=\"color: #bf4f24\">whenS<\/span> <span style=\"color: #794938\">::<\/span> <span style=\"color: #a71d5d;font-style: italic\">Selective<\/span> <span style=\"color: #234a97\">f<\/span> <span style=\"color: #794938\">=&gt;<\/span> <span style=\"color: #234a97\">f<\/span> <span style=\"color: #691c97\">Bool<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #234a97\">f<\/span> <span style=\"color: #b4371f\">()<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #234a97\">f<\/span> <span style=\"color: #b4371f\">()<\/span>\r\nwhenS x act <span style=\"color: #794938\">=<\/span> ifS x act (pure <span style=\"color: #811f24;font-weight: bold\">()<\/span>)\r\n\r\n<span style=\"color: #5a525f;font-style: italic\">-- | A lifted version of lazy Boolean OR.<\/span>\r\n<span style=\"color: #bf4f24\">(&lt;||&gt;)<\/span> <span style=\"color: #794938\">::<\/span> <span style=\"color: #a71d5d;font-style: italic\">Selective<\/span> <span style=\"color: #234a97\">f<\/span> <span style=\"color: #794938\">=&gt;<\/span> <span style=\"color: #234a97\">f<\/span> <span style=\"color: #691c97\">Bool<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #234a97\">f<\/span> <span style=\"color: #691c97\">Bool<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #234a97\">f<\/span> <span style=\"color: #691c97\">Bool<\/span>\r\n<span style=\"color: #bf4f24\">(&lt;||&gt;)<\/span> a b <span style=\"color: #794938\">=<\/span> ifS a (pure <span style=\"color: #b4371f\">True<\/span>) b\r\n<\/pre>\n<p>See more examples in <a href=\"https:\/\/github.com\/snowleopard\/selective\">the repository<\/a>. (Note: I recently renamed <span style=\"color: #000080\">handle<\/span> to <span style=\"color: #000080\">select<\/span>, and <span style=\"color: #000080\">select<\/span> to <span style=\"color: #000080\">branch<\/span> in the repository. Apologies for the confusion.)<\/p>\n<h3>Static analysis<\/h3>\n<p>Like applicative functors, selective functors can be analysed statically. As an example, consider the following useful data type <span style=\"color: #000080\">Validation<\/span>:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #794938\">data<\/span> <span style=\"color: #811f24;font-weight: bold\">Validation<\/span> e a <span style=\"color: #794938\">=<\/span> <span style=\"color: #811f24;font-weight: bold\">Failure<\/span> e <span style=\"color: #794938\">|<\/span> <span style=\"color: #811f24;font-weight: bold\">Success<\/span> a\r\n<span style=\"color: #794938\">    deriving<\/span> (<span style=\"color: #bf4f24\">Functor<\/span>, <span style=\"color: #bf4f24\">Show<\/span>)\r\n\r\n<span style=\"color: #794938\">instance<\/span> <span style=\"color: #a71d5d;font-style: italic\">Semigroup<\/span> <span style=\"color: #234a97\">e<\/span> <span style=\"color: #794938\">=&gt;<\/span> <span style=\"color: #a71d5d;font-style: italic\">Applicative<\/span> (<span style=\"color: #a71d5d;font-style: italic\">Validation<\/span> <span style=\"color: #234a97\">e<\/span>) <span style=\"color: #794938\">where<\/span>\r\n    pure <span style=\"color: #794938\">=<\/span> <span style=\"color: #811f24;font-weight: bold\">Success<\/span>\r\n    <span style=\"color: #811f24;font-weight: bold\">Failure<\/span> e1 <span style=\"color: #794938\">&lt;<\/span>*<span style=\"color: #794938\">&gt;<\/span> <span style=\"color: #811f24;font-weight: bold\">Failure<\/span> e2 <span style=\"color: #794938\">=<\/span> <span style=\"color: #811f24;font-weight: bold\">Failure<\/span> (e1 <span style=\"color: #794938\">&lt;&gt;<\/span> e2)\r\n    <span style=\"color: #811f24;font-weight: bold\">Failure<\/span> e1 <span style=\"color: #794938\">&lt;<\/span>*<span style=\"color: #794938\">&gt;<\/span> <span style=\"color: #811f24;font-weight: bold\">Success<\/span> _  <span style=\"color: #794938\">=<\/span> <span style=\"color: #811f24;font-weight: bold\">Failure<\/span> e1\r\n    <span style=\"color: #811f24;font-weight: bold\">Success<\/span> _  <span style=\"color: #794938\">&lt;<\/span>*<span style=\"color: #794938\">&gt;<\/span> <span style=\"color: #811f24;font-weight: bold\">Failure<\/span> e2 <span style=\"color: #794938\">=<\/span> <span style=\"color: #811f24;font-weight: bold\">Failure<\/span> e2\r\n    <span style=\"color: #811f24;font-weight: bold\">Success<\/span> f  <span style=\"color: #794938\">&lt;<\/span>*<span style=\"color: #794938\">&gt;<\/span> <span style=\"color: #811f24;font-weight: bold\">Success<\/span> a  <span style=\"color: #794938\">=<\/span> <span style=\"color: #811f24;font-weight: bold\">Success<\/span> (f a)\r\n\r\n<span style=\"color: #794938\">instance<\/span> <span style=\"color: #a71d5d;font-style: italic\">Semigroup<\/span> <span style=\"color: #234a97\">e<\/span> <span style=\"color: #794938\">=&gt;<\/span> <span style=\"color: #a71d5d;font-style: italic\">Selective<\/span> (<span style=\"color: #a71d5d;font-style: italic\">Validation<\/span> <span style=\"color: #234a97\">e<\/span>) <span style=\"color: #794938\">where<\/span>\r\n    handle (<span style=\"color: #811f24;font-weight: bold\">Success<\/span> (<span style=\"color: #b4371f\">Right<\/span> b)) _ <span style=\"color: #794938\">=<\/span> <span style=\"color: #811f24;font-weight: bold\">Success<\/span> b\r\n    handle (<span style=\"color: #811f24;font-weight: bold\">Success<\/span> (<span style=\"color: #b4371f\">Left<\/span>  a)) f <span style=\"color: #794938\">=<\/span> <span style=\"color: #811f24;font-weight: bold\">Success<\/span> (<span style=\"color: #794938\">$<\/span>a) <span style=\"color: #794938\">&lt;<\/span>*<span style=\"color: #794938\">&gt;<\/span> f\r\n    handle (<span style=\"color: #811f24;font-weight: bold\">Failure<\/span> e        ) _ <span style=\"color: #794938\">=<\/span> <span style=\"color: #811f24;font-weight: bold\">Failure<\/span> e\r\n<\/pre>\n<p>This data type is used for validating complex data: if reading one or more fields has failed, all errors are accumulated (using the operator <span style=\"color: #000080\">&lt;&gt;<\/span> from the semigroup <span style=\"color: #000080\">e<\/span>)\u00a0to be reported together. By defining the <span style=\"color: #000080\">Selective<\/span> instance, we can now validate data with conditions. Below we define a function to construct a <span style=\"color: #000080\">Shape<\/span> (a <span style=\"color: #000080\">Circle<\/span> or a <span style=\"color: #000080\">Rectangle<\/span>) given a choice of the shape <span style=\"color: #000080\">s :: f Bool<\/span>\u00a0and the shape&#8217;s parameters (<span style=\"color: #000080\">Radius<\/span>, <span style=\"color: #000080\">Width<\/span> and <span style=\"color: #000080\">Height<\/span>) in an arbitrary selective context <span style=\"color: #000080\">f<\/span>.<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #794938\">type<\/span> <span style=\"color: #811f24;font-weight: bold\">Radius<\/span> <span style=\"color: #794938\">=<\/span> <span style=\"color: #811f24;font-weight: bold\">Int<\/span>\r\n<span style=\"color: #794938\">type<\/span> <span style=\"color: #811f24;font-weight: bold\">Width<\/span>  <span style=\"color: #794938\">=<\/span> <span style=\"color: #811f24;font-weight: bold\">Int<\/span>\r\n<span style=\"color: #794938\">type<\/span> <span style=\"color: #811f24;font-weight: bold\">Height<\/span> <span style=\"color: #794938\">=<\/span> <span style=\"color: #811f24;font-weight: bold\">Int<\/span>\r\n\r\n<span style=\"color: #794938\">data<\/span> <span style=\"color: #811f24;font-weight: bold\">Shape<\/span> <span style=\"color: #794938\">=<\/span> <span style=\"color: #811f24;font-weight: bold\">Circle<\/span> <span style=\"color: #811f24;font-weight: bold\">Radius<\/span> <span style=\"color: #794938\">|<\/span> <span style=\"color: #811f24;font-weight: bold\">Rectangle<\/span> <span style=\"color: #811f24;font-weight: bold\">Width<\/span> <span style=\"color: #811f24;font-weight: bold\">Height<\/span> <span style=\"color: #794938\">deriving<\/span> <span style=\"color: #811f24;font-weight: bold\">Show<\/span>\r\n\r\n<span style=\"color: #bf4f24\">shape<\/span> <span style=\"color: #794938\">::<\/span> <span style=\"color: #a71d5d;font-style: italic\">Selective<\/span> <span style=\"color: #234a97\">f<\/span> <span style=\"color: #794938\">=&gt;<\/span>\r\n    f <span style=\"color: #811f24;font-weight: bold\">Bool<\/span> <span style=\"color: #794938\">-&gt;<\/span> f <span style=\"color: #811f24;font-weight: bold\">Radius<\/span> <span style=\"color: #794938\">-&gt;<\/span> f <span style=\"color: #811f24;font-weight: bold\">Width<\/span> <span style=\"color: #794938\">-&gt;<\/span> f <span style=\"color: #811f24;font-weight: bold\">Height<\/span> <span style=\"color: #794938\">-&gt;<\/span> f <span style=\"color: #811f24;font-weight: bold\">Shape<\/span>\r\nshape s r w h <span style=\"color: #794938\">=<\/span> ifS s (<span style=\"color: #811f24;font-weight: bold\">Circle<\/span> <span style=\"color: #794938\">&lt;$&gt;<\/span> r) (<span style=\"color: #811f24;font-weight: bold\">Rectangle<\/span> <span style=\"color: #794938\">&lt;$&gt;<\/span> w <span style=\"color: #794938\">&lt;<\/span>*<span style=\"color: #794938\">&gt;<\/span> h)\r\n<\/pre>\n<p>We choose <span style=\"color: #000080\">f = Validation [String]<\/span>\u00a0to report the errors that occurred when reading values. Let&#8217;s see how it works.<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\">\u03bb<span style=\"color: #794938\">&gt;<\/span> shape (<span style=\"color: #811f24;font-weight: bold\">Success<\/span> <span style=\"color: #b4371f\">True<\/span>) (<span style=\"color: #811f24;font-weight: bold\">Success<\/span> <span style=\"color: #811f24;font-weight: bold\">10<\/span>)\r\n    (<span style=\"color: #811f24;font-weight: bold\">Failure<\/span> [<span style=\"color: #0b6125\">\"no width\"<\/span>]) (<span style=\"color: #811f24;font-weight: bold\">Failure<\/span> [<span style=\"color: #0b6125\">\"no height\"<\/span>])\r\n<span style=\"color: #811f24;font-weight: bold\">Success<\/span> (<span style=\"color: #811f24;font-weight: bold\">Circle<\/span> <span style=\"color: #811f24;font-weight: bold\">10<\/span>)\r\n\r\n\u03bb<span style=\"color: #794938\">&gt;<\/span> shape (<span style=\"color: #811f24;font-weight: bold\">Success<\/span> <span style=\"color: #b4371f\">False<\/span>) (<span style=\"color: #811f24;font-weight: bold\">Failure<\/span> [<span style=\"color: #0b6125\">\"no radius\"<\/span>])\r\n    (<span style=\"color: #811f24;font-weight: bold\">Success<\/span> <span style=\"color: #811f24;font-weight: bold\">20<\/span>) (<span style=\"color: #811f24;font-weight: bold\">Success<\/span> <span style=\"color: #811f24;font-weight: bold\">30<\/span>)\r\n<span style=\"color: #811f24;font-weight: bold\">Success<\/span> (<span style=\"color: #811f24;font-weight: bold\">Rectangle<\/span> <span style=\"color: #811f24;font-weight: bold\">20<\/span> <span style=\"color: #811f24;font-weight: bold\">30<\/span>)\r\n\r\n\u03bb<span style=\"color: #794938\">&gt;<\/span> shape (<span style=\"color: #811f24;font-weight: bold\">Success<\/span> <span style=\"color: #b4371f\">False<\/span>) (<span style=\"color: #811f24;font-weight: bold\">Failure<\/span> [<span style=\"color: #0b6125\">\"no radius\"<\/span>])\r\n     (<span style=\"color: #811f24;font-weight: bold\">Success<\/span> <span style=\"color: #811f24;font-weight: bold\">20<\/span>) (<span style=\"color: #811f24;font-weight: bold\">Failure<\/span> [<span style=\"color: #0b6125\">\"no height\"<\/span>])\r\n<span style=\"color: #811f24;font-weight: bold\">Failure<\/span> [<span style=\"color: #0b6125\">\"no height\"<\/span>]\r\n\r\n\u03bb<span style=\"color: #794938\">&gt;<\/span> shape (<span style=\"color: #811f24;font-weight: bold\">Success<\/span> <span style=\"color: #b4371f\">False<\/span>) (<span style=\"color: #811f24;font-weight: bold\">Failure<\/span> [<span style=\"color: #0b6125\">\"no radius\"<\/span>])\r\n    (<span style=\"color: #811f24;font-weight: bold\">Failure<\/span> [<span style=\"color: #0b6125\">\"no width\"<\/span>]) (<span style=\"color: #811f24;font-weight: bold\">Failure<\/span> [<span style=\"color: #0b6125\">\"no height\"<\/span>])\r\n<span style=\"color: #811f24;font-weight: bold\">Failure<\/span> [<span style=\"color: #0b6125\">\"no width\"<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #0b6125\">\"no height\"<\/span>]\r\n\r\n\u03bb<span style=\"color: #794938\">&gt;<\/span> shape (<span style=\"color: #811f24;font-weight: bold\">Failure<\/span> [<span style=\"color: #0b6125\">\"no choice\"<\/span>]) (<span style=\"color: #811f24;font-weight: bold\">Failure<\/span> [<span style=\"color: #0b6125\">\"no radius\"<\/span>])\r\n    (<span style=\"color: #811f24;font-weight: bold\">Success<\/span> <span style=\"color: #811f24;font-weight: bold\">20<\/span>) (<span style=\"color: #811f24;font-weight: bold\">Failure<\/span> [<span style=\"color: #0b6125\">\"no height\"<\/span>])\r\n<span style=\"color: #811f24;font-weight: bold\">Failure<\/span> [<span style=\"color: #0b6125\">\"no choice\"<\/span>]\r\n<\/pre>\n<p>In the last example, since we failed to parse which shape has been chosen, we do not report any subsequent errors. But it doesn&#8217;t mean we are short-circuiting the validation. We will continue accumulating errors as soon as we get out of the opaque conditional:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #bf4f24\">twoShapes<\/span> <span style=\"color: #794938\">::<\/span> <span style=\"color: #a71d5d;font-style: italic\">Selective<\/span> <span style=\"color: #234a97\">f<\/span> <span style=\"color: #794938\">=&gt;<\/span> <span style=\"color: #234a97\">f<\/span> <span style=\"color: #a71d5d;font-style: italic\">Shape<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #234a97\">f<\/span> <span style=\"color: #a71d5d;font-style: italic\">Shape<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #234a97\">f<\/span> (<span style=\"color: #a71d5d;font-style: italic\">Shape<\/span>, <span style=\"color: #a71d5d;font-style: italic\">Shape<\/span>)\r\ntwoShapes s1 s2 <span style=\"color: #794938\">=<\/span> <span style=\"color: #bf4f24\">(,)<\/span> <span style=\"color: #794938\">&lt;$&gt;<\/span> s1 <span style=\"color: #794938\">&lt;<\/span>*<span style=\"color: #794938\">&gt;<\/span> s2\r\n\r\n\u03bb<span style=\"color: #794938\">&gt;<\/span> s1 <span style=\"color: #794938\">=<\/span> shape (<span style=\"color: #811f24;font-weight: bold\">Failure<\/span> [<span style=\"color: #0b6125\">\"no choice 1\"<\/span>]) (<span style=\"color: #811f24;font-weight: bold\">Failure<\/span> [<span style=\"color: #0b6125\">\"no radius 1\"<\/span>])\r\n    (<span style=\"color: #811f24;font-weight: bold\">Success<\/span> <span style=\"color: #811f24;font-weight: bold\">20<\/span>) (<span style=\"color: #811f24;font-weight: bold\">Failure<\/span> [<span style=\"color: #0b6125\">\"no height 1\"<\/span>])\r\n\u03bb<span style=\"color: #794938\">&gt;<\/span> s2 <span style=\"color: #794938\">=<\/span> shape (<span style=\"color: #811f24;font-weight: bold\">Success<\/span> <span style=\"color: #b4371f\">False<\/span>) (<span style=\"color: #811f24;font-weight: bold\">Failure<\/span> [<span style=\"color: #0b6125\">\"no radius 2\"<\/span>])\r\n    (<span style=\"color: #811f24;font-weight: bold\">Success<\/span> <span style=\"color: #811f24;font-weight: bold\">20<\/span>) (<span style=\"color: #811f24;font-weight: bold\">Failure<\/span> [<span style=\"color: #0b6125\">\"no height 2\"<\/span>])\r\n\u03bb<span style=\"color: #794938\">&gt;<\/span> twoShapes s1 s2\r\n<span style=\"color: #811f24;font-weight: bold\">Failure<\/span> [<span style=\"color: #0b6125\">\"no choice 1\"<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #0b6125\">\"no height 2\"<\/span>]\r\n<\/pre>\n<p>Another example of static analysis of selective functors is the <span style=\"color: #000080\">Task<\/span> abstraction from\u00a0<a href=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/the-task-abstraction\/\">the previous blog post<\/a>.<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #794938\">instance<\/span> <span style=\"color: #a71d5d;font-style: italic\">Monoid<\/span> <span style=\"color: #234a97\">m<\/span> <span style=\"color: #794938\">=&gt;<\/span> <span style=\"color: #a71d5d;font-style: italic\">Selective<\/span> (<span style=\"color: #a71d5d;font-style: italic\">Const<\/span> <span style=\"color: #234a97\">m<\/span>) <span style=\"color: #794938\">where<\/span>\r\n    handle <span style=\"color: #794938\">=<\/span> handleA\r\n\r\n<span style=\"color: #794938\">type<\/span> <span style=\"color: #811f24;font-weight: bold\">Task<\/span> c k v <span style=\"color: #794938\">=<\/span> forall f<span style=\"color: #794938\">.<\/span> c f <span style=\"color: #794938\">=&gt;<\/span> (k <span style=\"color: #794938\">-&gt;<\/span> f v) <span style=\"color: #794938\">-&gt;<\/span> k <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #811f24;font-weight: bold\">Maybe<\/span> (f v)\r\n\r\n<span style=\"color: #bf4f24\">dependencies<\/span> <span style=\"color: #794938\">::<\/span> <span style=\"color: #a71d5d;font-style: italic\">Task<\/span> <span style=\"color: #a71d5d;font-style: italic\">Selective<\/span> <span style=\"color: #234a97\">k<\/span> <span style=\"color: #234a97\">v<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #234a97\">k<\/span> <span style=\"color: #794938\">-&gt;<\/span> [<span style=\"color: #234a97\">k<\/span>]\r\ndependencies task key <span style=\"color: #794938\">=<\/span> <span style=\"color: #794938\">case<\/span> task (<span style=\"color: #794938\">\\<\/span>k <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #811f24;font-weight: bold\">Const<\/span> [k]) key <span style=\"color: #794938\">of<\/span>\r\n                            <span style=\"color: #b4371f\">Nothing<\/span>         <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #811f24;font-weight: bold\">[]<\/span>\r\n                            <span style=\"color: #b4371f\">Just<\/span> (<span style=\"color: #811f24;font-weight: bold\">Const<\/span> ks) <span style=\"color: #794938\">-&gt;<\/span> ks\r\n<\/pre>\n<p>The definition of the <span style=\"color: #000080\">Selective<\/span> instance for the <span style=\"color: #000080\">Const<\/span> functor simply falls back to the applicative <span style=\"color: #000080\">handleA<\/span>, which allows us to extract the static structure of any selective computation very similarly to how this is done with applicative computations. In particular, the function <span style=\"color: #000080\">dependencies<\/span> returns an approximation of dependencies of a given key: instead of ignoring opaque conditional statements as in <span style=\"color: #000080\">Validation<\/span>, we choose to inspect <em>both<\/em> branches collecting dependencies from both of them.<\/p>\n<p>Here is an example from the <span style=\"color: #000080\">Task<\/span>\u00a0<a href=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/the-task-abstraction\/\">blog post<\/a>, where we used the\u00a0<span style=\"color: #000080\">Monad<\/span> abstraction to express a spreadsheet with two formulas:\u00a0<span style=\"color: #000080\">B1 = IF(C1=1,B2,A2)<\/span> and\u00a0<span style=\"color: #000080\">B2 = IF(C1=1,A1,B1)<\/span>.<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #bf4f24\">task<\/span> <span style=\"color: #794938\">::<\/span> <span style=\"color: #a71d5d;font-style: italic\">Task<\/span> <span style=\"color: #a71d5d;font-style: italic\">Monad<\/span> <span style=\"color: #691c97\">String<\/span> <span style=\"color: #691c97\">Integer<\/span>\r\ntask fetch <span style=\"color: #0b6125\">\"B1\"<\/span> <span style=\"color: #794938\">=<\/span> <span style=\"color: #b4371f\">Just<\/span> <span style=\"color: #794938\">$<\/span> <span style=\"color: #794938\">do<\/span> c1 <span style=\"color: #794938\">&lt;-<\/span> fetch <span style=\"color: #0b6125\">\"C1\"<\/span>\r\n                            <span style=\"color: #794938\">if<\/span> c1 <span style=\"color: #794938\">==<\/span> <span style=\"color: #811f24;font-weight: bold\">1<\/span> <span style=\"color: #794938\">then<\/span> fetch <span style=\"color: #0b6125\">\"B2\"<\/span>\r\n                                       <span style=\"color: #794938\">else<\/span> fetch <span style=\"color: #0b6125\">\"A2\"<\/span>\r\ntask fetch <span style=\"color: #0b6125\">\"B2\"<\/span> <span style=\"color: #794938\">=<\/span> <span style=\"color: #b4371f\">Just<\/span> <span style=\"color: #794938\">$<\/span> <span style=\"color: #794938\">do<\/span> c1 <span style=\"color: #794938\">&lt;-<\/span> fetch <span style=\"color: #0b6125\">\"C1\"<\/span>\r\n                            <span style=\"color: #794938\">if<\/span> c1 <span style=\"color: #794938\">==<\/span> <span style=\"color: #811f24;font-weight: bold\">1<\/span> <span style=\"color: #794938\">then<\/span> fetch <span style=\"color: #0b6125\">\"A1\"<\/span>\r\n                                       <span style=\"color: #794938\">else<\/span> fetch <span style=\"color: #0b6125\">\"B1\"<\/span>\r\ntask _     _    <span style=\"color: #794938\">=<\/span> <span style=\"color: #b4371f\">Nothing<\/span>\r\n<\/pre>\n<p>Since this <span style=\"color: #000080\">task<\/span> description is monadic we could not analyse it statically. But now we can! All we need to do is rewrite it using <span style=\"color: #000080\">Selective<\/span>:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #bf4f24\">task<\/span> <span style=\"color: #794938\">::<\/span> <span style=\"color: #a71d5d;font-style: italic\">Task<\/span> <span style=\"color: #a71d5d;font-style: italic\">Selective<\/span> <span style=\"color: #691c97\">String<\/span> <span style=\"color: #691c97\">Integer<\/span>\r\ntask fetch <span style=\"color: #0b6125\">\"B1\"<\/span> <span style=\"color: #794938\">=<\/span> <span style=\"color: #b4371f\">Just<\/span> <span style=\"color: #794938\">$<\/span>\r\n    ifS ((<span style=\"color: #811f24;font-weight: bold\">1<\/span><span style=\"color: #794938\">==<\/span>) <span style=\"color: #794938\">&lt;$&gt;<\/span> fetch <span style=\"color: #0b6125\">\"C1\"<\/span>) (fetch <span style=\"color: #0b6125\">\"B2\"<\/span>) (fetch <span style=\"color: #0b6125\">\"A2\"<\/span>)\r\ntask fetch <span style=\"color: #0b6125\">\"B2\"<\/span> <span style=\"color: #794938\">=<\/span> <span style=\"color: #b4371f\">Just<\/span> <span style=\"color: #794938\">$<\/span>\r\n    ifS ((<span style=\"color: #811f24;font-weight: bold\">1<\/span><span style=\"color: #794938\">==<\/span>) <span style=\"color: #794938\">&lt;$&gt;<\/span> fetch <span style=\"color: #0b6125\">\"C1\"<\/span>) (fetch <span style=\"color: #0b6125\">\"A1\"<\/span>) (fetch <span style=\"color: #0b6125\">\"B1\"<\/span>)\r\ntask _     _    <span style=\"color: #794938\">=<\/span> <span style=\"color: #b4371f\">Nothing<\/span>\r\n<\/pre>\n<p>We can now apply the function <span style=\"color: #000080\">dependencies<\/span> defined above and draw the dependency graph using your favourite <a href=\"https:\/\/github.com\/snowleopard\/alga\">graph\u00a0library<\/a>:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\">\u03bb<span style=\"color: #794938\">&gt;<\/span> dependencies task <span style=\"color: #0b6125\">\"B1\"<\/span>\r\n[<span style=\"color: #0b6125\">\"A2\"<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #0b6125\">\"B2\"<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #0b6125\">\"C1\"<\/span>]\r\n\u03bb<span style=\"color: #794938\">&gt;<\/span> dependencies task <span style=\"color: #0b6125\">\"B2\"<\/span>\r\n[<span style=\"color: #0b6125\">\"A1\"<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #0b6125\">\"B1\"<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #0b6125\">\"C1\"<\/span>]\r\n\u03bb<span style=\"color: #794938\">&gt;<\/span> dependencies task <span style=\"color: #0b6125\">\"A1\"<\/span>\r\n<span style=\"color: #811f24;font-weight: bold\">[]<\/span>\r\n\r\n\u03bb<span style=\"color: #794938\">&gt;<\/span> <span style=\"color: #693a17\">writeFile<\/span> <span style=\"color: #0b6125\">\"task.dot\"<\/span> <span style=\"color: #794938\">$<\/span> exportAsIs <span style=\"color: #794938\">$<\/span> graph (dependencies task) <span style=\"color: #0b6125\">\"B1\"<\/span>\r\n\u03bb<span style=\"color: #794938\">&gt;<\/span> <span style=\"color: #794938\">:!<\/span> dot <span style=\"color: #794938\">-<\/span><span style=\"color: #811f24;font-weight: bold\">Tsvg<\/span> task<span style=\"color: #794938\">.<\/span>dot <span style=\"color: #794938\">-<\/span>o task<span style=\"color: #794938\">.<\/span>svg\r\n<\/pre>\n<p>This produces the graph below, which matches <a href=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/the-task-abstraction\/#graph\">the one<\/a> I had to draw manually last time, since I had no <span style=\"color: #000080\">Selective<\/span> to help me.<\/p>\n<p><a href=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/files\/2018\/06\/task.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-800\" src=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/files\/2018\/06\/task.png\" alt=\"Static analysis of selective functors\" width=\"257\" height=\"300\" srcset=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/files\/2018\/06\/task.png 800w, https:\/\/blogs.ncl.ac.uk\/andreymokhov\/files\/2018\/06\/task-257x300.png 257w, https:\/\/blogs.ncl.ac.uk\/andreymokhov\/files\/2018\/06\/task-768x896.png 768w\" sizes=\"auto, (max-width: 257px) 100vw, 257px\" \/><\/a><\/p>\n<h3>Laws<\/h3>\n<p>Instances of the <span style=\"color: #000080\">Selective<\/span> type class must satisfy a few laws to make it possible to refactor selective computations. These laws also allow us to establish a formal relation with the <span style=\"color: #000080\">Applicative<\/span> and <span style=\"color: #000080\">Monad<\/span> type classes. The laws are complex, but I couldn&#8217;t figure out how to simplify them. Please let me know if you find an improvement.<\/p>\n<ul>\n<li><span style=\"color: #000080\">(F1)<\/span> Apply a pure function to the result:\n<pre style=\"background: #f9f9f9;color: #080808\">f <span style=\"color: #794938\">&lt;$&gt;<\/span> handle x y <span style=\"color: #794938\">=<\/span> handle (second f <span style=\"color: #794938\">&lt;$&gt;<\/span> x) ((f <span style=\"color: #794938\">.<\/span>) <span style=\"color: #794938\">&lt;$&gt;<\/span> y)\r\n<\/pre>\n<\/li>\n<li><span style=\"color: #000080\">(F2)<\/span> Apply a pure function to the left (error) branch:\n<pre style=\"background: #f9f9f9;color: #080808\">handle (first f <span style=\"color: #794938\">&lt;$&gt;<\/span> x) y <span style=\"color: #794938\">=<\/span> handle x ((<span style=\"color: #794938\">.<\/span> f) <span style=\"color: #794938\">&lt;$&gt;<\/span> y)\r\n<\/pre>\n<\/li>\n<li><span style=\"color: #000080\">(F3)<\/span> Apply a pure function to the handler:\n<pre style=\"background: #f9f9f9;color: #080808\">handle x (f <span style=\"color: #794938\">&lt;$&gt;<\/span> y) <span style=\"color: #794938\">=\r\n<\/span>    handle (first (<span style=\"color: #693a17\">flip<\/span> f) <span style=\"color: #794938\">&lt;$&gt;<\/span> x) (<span style=\"color: #693a17\">flip<\/span> <span style=\"color: #bf4f24\">($)<\/span> <span style=\"color: #794938\">&lt;$&gt;<\/span> y)\r\n<\/pre>\n<\/li>\n<li><span style=\"color: #000080\">(P1)<\/span> Apply a pure handler:\n<pre style=\"background: #f9f9f9;color: #080808\">handle x (pure y) <span style=\"color: #794938\">=<\/span> either y <span style=\"color: #693a17\">id<\/span> <span style=\"color: #794938\">&lt;$&gt;<\/span> x\r\n<\/pre>\n<\/li>\n<li><span style=\"color: #000080\">(P2)<\/span> Handle a pure error:\n<pre style=\"background: #f9f9f9;color: #080808\">handle (pure (<span style=\"color: #b4371f\">Left<\/span> x)) y <span style=\"color: #794938\">=<\/span> (<span style=\"color: #794938\">$<\/span>x) <span style=\"color: #794938\">&lt;$&gt;<\/span> y\r\n<\/pre>\n<\/li>\n<li><span style=\"color: #000080\">(A1)<\/span> Associativity (in disguise):\n<pre style=\"background: #f9f9f9;color: #080808\">handle x (handle y z) <span style=\"color: #794938\">=<\/span>\r\n    handle (handle (f <span style=\"color: #794938\">&lt;$&gt;<\/span> x) (g <span style=\"color: #794938\">&lt;$&gt;<\/span> y)) (h <span style=\"color: #794938\">&lt;$&gt;<\/span> z)\r\n  <span style=\"color: #794938\">where<\/span>\r\n    f x <span style=\"color: #794938\">=<\/span> <span style=\"color: #b4371f\">Right<\/span> <span style=\"color: #794938\">&lt;$&gt;<\/span> x\r\n    g y <span style=\"color: #794938\">=<\/span> <span style=\"color: #794938\">\\<\/span>a <span style=\"color: #794938\">-&gt;<\/span> bimap (<span style=\"color: #794938\">,<\/span>a) (<span style=\"color: #794938\">$<\/span>a) y\r\n    h z <span style=\"color: #794938\">=<\/span> <span style=\"color: #693a17\">uncurry<\/span> z\r\n\r\n<span style=\"color: #5a525f;font-style: italic\">-- or in operator form with (&lt;*?) = handle<\/span>\r\n\r\nx <span style=\"color: #794938\">&lt;<\/span>*<span style=\"color: #794938\">?<\/span> (y <span style=\"color: #794938\">&lt;<\/span>*<span style=\"color: #794938\">?<\/span> z) <span style=\"color: #794938\">=<\/span> (f <span style=\"color: #794938\">&lt;$&gt;<\/span> x) <span style=\"color: #794938\">&lt;<\/span>*<span style=\"color: #794938\">?<\/span> (g <span style=\"color: #794938\">&lt;$&gt;<\/span> y) <span style=\"color: #794938\">&lt;<\/span>*<span style=\"color: #794938\">?<\/span> (h <span style=\"color: #794938\">&lt;$&gt;<\/span> z)\r\n\r\n<\/pre>\n<\/li>\n<\/ul>\n<p>Note that there is no law for handling a pure value, i.e. we do not require that the following holds:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\">handle (pure (<span style=\"color: #b4371f\">Right<\/span> x)) y <span style=\"color: #794938\">=<\/span> pure x\r\n<\/pre>\n<p>In particular, the following is allowed too:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\">handle (pure (<span style=\"color: #b4371f\">Right<\/span> x)) y <span style=\"color: #794938\">=<\/span> <span style=\"color: #693a17\">const<\/span> x <span style=\"color: #794938\">&lt;$&gt;<\/span> y\r\n<\/pre>\n<p>We therefore allow <span style=\"color: #000080\">handle<\/span> to be selective about effects in this case. If we insisted on adding the first version of the above law, that would rule out the useful <span style=\"color: #000080\">Const<\/span> instance. If we insisted on the second version of the law, we would essentially be back to <span style=\"color: #000080\">Applicative<\/span>.<\/p>\n<p>A consequence of the above laws is that <span style=\"color: #000080\">apS<\/span> satisfies <span style=\"color: #000080\">Applicative<\/span> laws (I do not have a formal proof, but you can find some proof sketches <a href=\"https:\/\/github.com\/snowleopard\/selective\/blob\/master\/src\/Control\/Selective\/Sketch.hs\">here<\/a>). Note that we choose not to require that <span style=\"color: #000080\">apS = &lt;*&gt;<\/span>,\u00a0since this forbids some interesting instances, such as <span style=\"color: #000080\">Validation<\/span> defined above.<\/p>\n<p>If <span style=\"color: #000080\">f<\/span> is also a <span style=\"color: #000080\">Monad<\/span>, we require that <span style=\"color: #000080\">handle = handleM<\/span>.<\/p>\n<p>Using the laws, it is possible to rewrite any selective computation into a normal form (the operator <span style=\"color: #000080\">+<\/span> denotes the sum type constructor):<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\">   f (a <span style=\"color: #794938\">+<\/span> b <span style=\"color: #794938\">+<\/span> <span style=\"color: #794938\">...<\/span> <span style=\"color: #794938\">+<\/span> z)    <span style=\"color: #5a525f;font-style: italic\">-- An initial value of a sum type<\/span>\r\n<span style=\"color: #794938\">-&gt;<\/span> f (a <span style=\"color: #794938\">-&gt;<\/span> (b <span style=\"color: #794938\">+<\/span> <span style=\"color: #794938\">...<\/span> <span style=\"color: #794938\">+<\/span> z)) <span style=\"color: #5a525f;font-style: italic\">-- How to handle a's<\/span>\r\n<span style=\"color: #794938\">-&gt;<\/span> f (b <span style=\"color: #794938\">-&gt;<\/span> (c <span style=\"color: #794938\">+<\/span> <span style=\"color: #794938\">...<\/span> <span style=\"color: #794938\">+<\/span> z)) <span style=\"color: #5a525f;font-style: italic\">-- How to handle b's<\/span>\r\n<span style=\"color: #794938\">...<\/span>\r\n<span style=\"color: #794938\">-&gt;<\/span> f (y <span style=\"color: #794938\">-&gt;<\/span> z)             <span style=\"color: #5a525f;font-style: italic\">-- How to handle y's<\/span>\r\n<span style=\"color: #794938\">-&gt;<\/span> f z                    <span style=\"color: #5a525f;font-style: italic\">-- The result<\/span>\r\n<\/pre>\n<p>In words, we start with a sum type and handle each alternative in turn, possibly skipping unnecessary handlers, until we end up with a resulting value.<\/p>\n<h3>Alternative formulations<\/h3>\n<p>There are other ways of expressing selective functors in Haskell and most of them are compositions of applicative functors and the <span style=\"color: #000080\">Either<\/span> monad. Below I list a few examples. All of them are required to perform effects from left to right.<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #5a525f;font-style: italic\">-- Composition of Applicative and Either monad<\/span>\r\n<span style=\"color: #794938\">class<\/span> <span style=\"color: #bf4f24\">Applicative<\/span> <span style=\"color: #234a97\">f<\/span> =&gt; <span style=\"color: #bf4f24\">SelectiveA<\/span> <span style=\"color: #234a97\">f<\/span> <span style=\"color: #794938\">where<\/span>\r\n    (<span style=\"color: #794938\">|<\/span>*<span style=\"color: #794938\">|<\/span>) <span style=\"color: #794938\">::<\/span> f (<span style=\"color: #811f24;font-weight: bold\">Either<\/span> e (a <span style=\"color: #794938\">-&gt;<\/span> b)) <span style=\"color: #794938\">-&gt;<\/span> f (<span style=\"color: #811f24;font-weight: bold\">Either<\/span> e a)\r\n<span style=\"color: #794938\">          -&gt;<\/span> f (<span style=\"color: #811f24;font-weight: bold\">Either<\/span> e b)\r\n\r\n<span style=\"color: #5a525f;font-style: italic\">-- Composition of Starry and Either monad<\/span>\r\n<span style=\"color: #5a525f;font-style: italic\">-- See: https:\/\/duplode.github.io\/posts\/applicative-archery.html<\/span>\r\n<span style=\"color: #794938\">class<\/span> <span style=\"color: #bf4f24\">Applicative<\/span> <span style=\"color: #234a97\">f<\/span> =&gt; <span style=\"color: #bf4f24\">SelectiveS<\/span> <span style=\"color: #234a97\">f<\/span> <span style=\"color: #794938\">where<\/span>\r\n    <span style=\"color: #bf4f24\">(|.|)<\/span> <span style=\"color: #794938\">::<\/span> f (<span style=\"color: #811f24;font-weight: bold\">Either<\/span> e (b <span style=\"color: #794938\">-&gt;<\/span> c)) <span style=\"color: #794938\">-&gt;<\/span> f (<span style=\"color: #811f24;font-weight: bold\">Either<\/span> e (a <span style=\"color: #794938\">-&gt;<\/span> b))\r\n          <span style=\"color: #794938\">-&gt;<\/span> f (<span style=\"color: #811f24;font-weight: bold\">Either<\/span> e (a <span style=\"color: #794938\">-&gt;<\/span> c))\r\n\r\n<span style=\"color: #5a525f;font-style: italic\">-- Composition of Monoidal and Either monad<\/span>\r\n<span style=\"color: #5a525f;font-style: italic\">-- See: http:\/\/blog.ezyang.com\/2012\/08\/applicative-functors\/<\/span>\r\n<span style=\"color: #794938\">class<\/span> <span style=\"color: #bf4f24\">Applicative<\/span> <span style=\"color: #234a97\">f<\/span> =&gt; <span style=\"color: #bf4f24\">SelectiveM<\/span> <span style=\"color: #234a97\">f<\/span> <span style=\"color: #794938\">where<\/span>\r\n    (<span style=\"color: #794938\">|<\/span>**<span style=\"color: #794938\">|<\/span>) <span style=\"color: #794938\">::<\/span> f (<span style=\"color: #811f24;font-weight: bold\">Either<\/span> e a) <span style=\"color: #794938\">-&gt;<\/span> f (<span style=\"color: #811f24;font-weight: bold\">Either<\/span> e b)\r\n<span style=\"color: #794938\">           -&gt;<\/span> f (<span style=\"color: #811f24;font-weight: bold\">Either<\/span> e (a<span style=\"color: #794938\">,<\/span> b))\r\n<\/pre>\n<p>I believe these formulations are equivalent to <span style=\"color: #000080\">Selective<\/span>, but I have not proved the equivalence formally. I like the minimalistic definition of the type class based on <span style=\"color: #000080\">handle<\/span>, but the above alternatives are worth consideration too. In particular, <span style=\"color: #000080\">SelectiveS<\/span> has a much nicer associativity law, which is just\u00a0<code>(x |.| y) |.| z = x |.| (y |.| z)<\/code>.<\/p>\n<h3>Concluding remarks<\/h3>\n<p>Selective functors are powerful: like monads they allows us to inspect values in an effectful context. Many monadic computations can therefore be rewritten using the <span style=\"color: #000080\">Selective<\/span> type class. Many, but not all! Crucially, selective functors cannot implement the function\u00a0<span style=\"color: #000080\">join<\/span>:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #bf4f24\">join<\/span> <span style=\"color: #794938\">::<\/span> <span style=\"color: #a71d5d;font-style: italic\">Selective<\/span> <span style=\"color: #234a97\">f<\/span> <span style=\"color: #794938\">=&gt;<\/span> <span style=\"color: #234a97\">f<\/span> (<span style=\"color: #234a97\">f<\/span> <span style=\"color: #234a97\">a<\/span>) <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #234a97\">f<\/span> <span style=\"color: #234a97\">a<\/span>\r\njoin <span style=\"color: #794938\">=<\/span> ... <span style=\"color: #5a525f;font-style: italic\">-- This puzzle has no solution, better solve 'select'!<\/span>\r\n<\/pre>\n<p>I&#8217;ve been playing with selective functors for a few weeks, and I have to admit that they are very difficult to work with. Pretty much all selective combinators involve mind-bending manipulations of <span style=\"color: #000080\">Left<\/span>s and <span style=\"color: #000080\">Right<\/span>s, with careful consideration of which effects are necessary. I hope all this complexity can be hidden in a library.<\/p>\n<p>I haven&#8217;t yet looked into performance issues, but it\u00a0is quite likely that it will be necessary to add more methods to the type class, so that their default implementations can be replaced with more efficient ones on instance-by-instance basis (similar optimisations are done with <span style=\"color: #000080\">Monad<\/span> and <span style=\"color: #000080\">Applicative<\/span>).<\/p>\n<p>Have you come across selective functors before? The definition of the type class is very simple, so somebody must have looked at it earlier.<\/p>\n<p>Also, do you have any other interesting use-cases for selective functors?<\/p>\n<p>Big thanks to Arseniy Alekseyev, Ulan Degenbaev and Georgy Lukyanov for useful discussions, which led to this blog post.<\/p>\n<h5 id=\"footnotes\">Footnotes and updates<\/h5>\n<p><span style=\"color: #000080\"><sup>(*)<\/sup><\/span>\u00a0As rightly pointed out by\u00a0<a class=\"author may-blank id-t2_byzre\" href=\"https:\/\/www.reddit.com\/user\/Darwin226\">Darwin226<\/a> in <a href=\"https:\/\/www.reddit.com\/r\/haskell\/comments\/8u81bg\/selective_applicative_functors\/\">the reddit discussion<\/a>, <span style=\"color: #000080\">handle = handleA<\/span>\u00a0gives a valid <span style=\"color: #000080\">Selective<\/span> instance for any <span style=\"color: #000080\">Applicative<\/span>, therefore calling it less powerful may be questionable. However, I would like to claim that <span style=\"color: #000080\">Selective<\/span>\u00a0does provide additional power: it gives us vocabulary to talk about <em>unnecessary effects<\/em>. We might want to be able to express three different ideas:<\/p>\n<ol>\n<li>Express the requirement that <span style=\"color: #000080\"><em>all effects must be performed<\/em><\/span>. This corresponds to the\u00a0<span style=\"color: #000080\">Applicative<\/span>\u00a0type class and <span style=\"color: #000080\">handleA<\/span>. There is no way to distinguish necessary effects from unnecessary ones in the <span style=\"color: #000080\">Applicative<\/span> setting.<\/li>\n<li>Express the requirement that <span style=\"color: #000080\"><em>unnecessary effects\u00a0must\u00a0be skipped<\/em><\/span>. This is a stricter version of <span style=\"color: #000080\">Selective<\/span>, which corresponds to <span style=\"color: #000080\">handleM<\/span>.<\/li>\n<li>Express the requirement that <span style=\"color: #000080\"><em>unnecessary effects\u00a0may\u00a0be skipped<\/em><\/span>. This is the version of <span style=\"color: #000080\">Selective<\/span> presented in this blog post: <span style=\"color: #000080\">handle<\/span> is allowed to be anywhere in the range from <span style=\"color: #000080\">handleA<\/span> to <span style=\"color: #000080\">handleM<\/span>.<\/li>\n<\/ol>\n<p>I think all three ideas are useful, and it is very interesting to study the stricter version of <span style=\"color: #000080\">Selective\u00a0<\/span>too. I&#8217;d be interested in hearing suggestions for the corresponding set of laws. The following two laws seem sensible:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\">handle (<span style=\"color: #b4371f\">Left<\/span>  <span style=\"color: #794938\">&lt;$&gt;<\/span> x) f <span style=\"color: #794938\">=<\/span> <span style=\"color: #693a17\">flip<\/span> <span style=\"color: #bf4f24\">($)<\/span> <span style=\"color: #794938\">&lt;$&gt;<\/span> x <span style=\"color: #794938\">&lt;<\/span>*<span style=\"color: #794938\">&gt;<\/span> f\r\nhandle (<span style=\"color: #b4371f\">Right<\/span> <span style=\"color: #794938\">&lt;$&gt;<\/span> x) f <span style=\"color: #794938\">=<\/span> x\r\n<\/pre>\n<form id=\"form-t1_e1ddv36ua5\" class=\"usertext warn-on-unload\" action=\"https:\/\/www.reddit.com\/r\/haskell\/comments\/8u81bg\/selective_applicative_functors\/#\">\n<div class=\"usertext-body may-blank-within md-container \">\n<div class=\"md\">\n<p>Note that the <span style=\"color: #000080\">Const<\/span> and <span style=\"color: #000080\">Validation<\/span> instances defined above do not satisfy these laws.<\/p>\n<p>Note also that\u00a0<span style=\"color: #000000\"><em>efficiency<\/em> <\/span>is an engineering notion full of tradeoffs and it might not always be obvious what is more efficient: to skip an unnecessary effect or to perform it and discard unused results. For example,\u00a0if you have parallelism, you might in some cases prefer to start the evaluation of both arguments of <span style=\"color: #000080\">handle<\/span> in parallel to speed up the error branch. The stricter version of selective functors forbids such optimisations.<\/p>\n<\/div>\n<\/div>\n<\/form>\n","protected":false},"excerpt":{"rendered":"<p>Update: I have written a paper about selective applicative functors, and it completely supersedes this blog post (it also uses a slightly different notation). You should read the paper instead. I often need a Haskell abstraction that supports conditions (like Monad) yet can still be statically analysed (like Applicative). In such cases people typically point &hellip; <a href=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/selective\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Selective applicative functors<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1174,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6,3],"tags":[4],"class_list":["post-777","post","type-post","status-publish","format-standard","hentry","category-coding","category-thinking","tag-haskell"],"_links":{"self":[{"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/posts\/777","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/users\/1174"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/comments?post=777"}],"version-history":[{"count":32,"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/posts\/777\/revisions"}],"predecessor-version":[{"id":1210,"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/posts\/777\/revisions\/1210"}],"wp:attachment":[{"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/media?parent=777"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/categories?post=777"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/tags?post=777"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}