{"id":671,"date":"2018-03-26T15:27:19","date_gmt":"2018-03-26T14:27:19","guid":{"rendered":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/?p=671"},"modified":"2019-05-02T20:37:23","modified_gmt":"2019-05-02T19:37:23","slug":"the-task-abstraction","status":"publish","type":"post","link":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/the-task-abstraction\/","title":{"rendered":"The Task abstraction"},"content":{"rendered":"<p>Neil Mitchell, Simon Peyton Jones and I have just finished a paper describing a systematic and executable framework for developing and comparing build systems. The paper and associated code are available here: <a href=\"https:\/\/github.com\/snowleopard\/build\">https:\/\/github.com\/snowleopard\/build<\/a>. The code is not yet well documented and polished, but I&#8217;ll bring it in a good shape in April. You can learn more about the motivation behind the project <a href=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/cloud-and-dynamic-builds\/\">here<\/a>.<\/p>\n<p>(Update: the paper got accepted to ICFP! Read the <a href=\"https:\/\/dl.acm.org\/ft_gateway.cfm?id=3236774\">PDF<\/a>, watch the <a href=\"https:\/\/www.youtube.com\/watch?v=BQVT6wiwCxM\">talk<\/a>.)<\/p>\n<p>In this blog post I would like to share one interesting abstraction that we came up with to describe build tasks:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><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)<\/pre>\n<p>A <span style=\"color: #00007f\">Task<\/span> is completely isolated from the world of compilers, file systems, dependency graphs, caches, and all other complexities of real build systems. It just computes the value of a key <span style=\"color: #00007f\">k<\/span>, in a side-effect-free way, using a callback of type\u00a0<span style=\"color: #00007f\">k \u2192 f v<\/span> to find the values of its dependencies. One simple example of a callback is Haskell&#8217;s <a href=\"http:\/\/hackage.haskell.org\/package\/base\/docs\/Prelude.html#v:readFile\">readFile function<\/a>: as one can see from its type <span style=\"color: #00007f\">FilePath \u2192 IO String<\/span>, given a key (a file path <span style=\"color: #00007f\">k =\u00a0FilePath<\/span>) it can find its value (the file contents of type <span style=\"color: #00007f\">v = String<\/span>) by performing arbitrary IO effects (hence,\u00a0<span style=\"color: #00007f\">f = IO<\/span>). We require task descriptions to be polymorhic in <span style=\"color: #00007f\">f<\/span>, so that we can reuse them in different computational contexts <span style=\"color: #00007f\">f<\/span> without rewriting from scratch.<\/p>\n<p><!--more--><\/p>\n<p>This highly-abstracted type is best introduced by an example. Consider the following Excel spreadsheet (yes, Excel is a build system in disguise):<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\">A1: 10     B1: A1 + A2\r\nA2: 20     B2: B1 * 2<\/pre>\n<p>Here cell <span style=\"color: #00007f\">A1<\/span> contains the value <span style=\"color: #00007f\">10<\/span>, cell <span style=\"color: #00007f\">B1<\/span> contains the formula <span style=\"color: #00007f\">A1 + A2<\/span>, etc. We can represent the formulae (i.e. <em>build tasks<\/em>) of this spreadsheet with the following task description:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #bf4f24\">sprsh1<\/span> <span style=\"color: #794938\">::<\/span> <span style=\"color: #a71d5d;font-style: italic\">Task<\/span> <span style=\"color: #a71d5d;font-style: italic\">Applicative<\/span> <span style=\"color: #691c97\">String<\/span> <span style=\"color: #691c97\">Integer<\/span>\r\nsprsh1 fetch <span style=\"color: #0b6125\">\"B1\"<\/span> <span style=\"color: #794938\">=<\/span> <span style=\"color: #b4371f\">Just<\/span> (<span style=\"color: #bf4f24\">(+)<\/span>  <span style=\"color: #794938\">&lt;$&gt;<\/span> fetch <span style=\"color: #0b6125\">\"A1\"<\/span> <span style=\"color: #794938\">&lt;<\/span>*<span style=\"color: #794938\">&gt;<\/span> fetch <span style=\"color: #0b6125\">\"A2\"<\/span>)\r\nsprsh1 fetch <span style=\"color: #0b6125\">\"B2\"<\/span> <span style=\"color: #794938\">=<\/span> <span style=\"color: #b4371f\">Just<\/span> ((*<span style=\"color: #811f24;font-weight: bold\">2<\/span>) <span style=\"color: #794938\">&lt;$&gt;<\/span> fetch <span style=\"color: #0b6125\">\"B1\"<\/span>)\r\nsprsh1 _     _    <span style=\"color: #794938\">=<\/span> <span style=\"color: #b4371f\">Nothing<\/span>\r\n<\/pre>\n<p>We instantiate the type of <em>keys<\/em> <span style=\"color: #00007f\">k<\/span> with <span style=\"color: #00007f\">String<\/span> (cell names), and the type of <em>values<\/em> <span style=\"color: #00007f\">v<\/span> with <span style=\"color: #00007f\">Integer<\/span> (real spreadsheets contain a wider range of values, of course). The task description <span style=\"color: #00007f\">sprsh1<\/span> embodies all the formulae of the spreadsheet, but not the input values. Like every <span style=\"color: #00007f\">Task<\/span>, <span style=\"color: #00007f\">sprsh1<\/span> is given a <em>callback<\/em> <span style=\"color: #00007f\">fetch<\/span> and a key. It pattern-matches on the key to see if it has a task description (a formula) for it. If not, it returns <span style=\"color: #00007f\">Nothing<\/span>, indicating that the key is an <em>input<\/em>. If there is a formula in the cell, it computes the value of the formula, using <span style=\"color: #00007f\">fetch<\/span> to find the value of any keys on which it depends.<\/p>\n<p>The definition of <span style=\"color: #00007f\">Task<\/span> and the above example look a bit mysterious. Why do we require <span style=\"color: #00007f\">Task<\/span> to be polymorphic in the type constructor <span style=\"color: #00007f\">f<\/span>? Why do we choose the <span style=\"color: #00007f\">c = Applicative<\/span> constraint? The answer is that given one task description, we would like to explore many different build systems that can build it and it turns out that each of them will use a different <span style=\"color: #00007f\">f<\/span>. Furthermore, we found that constraints <span style=\"color: #00007f\">c<\/span> classify build tasks in a very interesting way:<\/p>\n<ul>\n<li><span style=\"color: #00007f\">Task Applicative<\/span>:\u00a0In <span style=\"color: #00007f\">sprsh1<\/span> we needed only <span style=\"color: #00007f\">Applicative<\/span> operations, expressing the fact that the dependencies between cells can be determined <em>statically<\/em>; that is, by looking at the formulae, without \u201ccomputing\u201d them &#8212; we&#8217;ll demonstrate this later.<\/li>\n<li><span style=\"color: #00007f\">Task Monad<\/span>: some tasks\u00a0cannot be expressed using\u00a0only <span style=\"color: #00007f\">Applicative<\/span> operations, since they inspect actual values and can take different computation paths with different dependencies. Dependencies of such tasks are <em>dynamic<\/em>, i.e. they cannot be determined statically.<\/li>\n<li><span style=\"color: #00007f\"> Task Functor<\/span> is somewhat degenerate: the task description cannot even use the application operator <span style=\"color: #00007f\">&lt;*&gt;<\/span>, which limits dependencies to a single linear chain. Functorial tasks are easy to build, and are somewhat reminiscent of <a href=\"https:\/\/en.wikipedia.org\/wiki\/Tail_call\">tail recursion<\/a>.<\/li>\n<li><span style=\"color: #00007f\">Task Alternative<\/span>, <span style=\"color: #00007f\">Task MonadPlus<\/span> and their variants can be used for describing tasks with\u00a0non-determinism.<\/li>\n<\/ul>\n<p>Now let&#8217;s look at some examples of what we can do with tasks.<\/p>\n<h3>Compute<\/h3>\n<p>Given a <span style=\"color: #00007f\">task<\/span>, we can <span style=\"color: #00007f\">compute<\/span> the value corresponding to a given <span style=\"color: #00007f\">key<\/span> by providing a pure <span style=\"color: #00007f\">store<\/span>\u00a0function that associates keys to values:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #bf4f24\">compute<\/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: #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\">v<\/span>) <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #234a97\">k<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #691c97\">Maybe<\/span> <span style=\"color: #234a97\">v<\/span>\r\ncompute task store <span style=\"color: #794938\">=<\/span> <span style=\"color: #693a17\">fmap<\/span> runIdentity <span style=\"color: #794938\">.<\/span> task (<span style=\"color: #811f24;font-weight: bold\">Identity<\/span> <span style=\"color: #794938\">.<\/span> store)\r\n<\/pre>\n<p>Here we do not need any effects in the <span style=\"color: #00007f\">fetch<\/span> callback to <span style=\"color: #00007f\">task<\/span>, so we can use the standard Haskell <a href=\"https:\/\/hackage.haskell.org\/package\/base\/docs\/Data-Functor-Identity.html\">Identity monad<\/a> (I first learned about this trivial monad from <a href=\"http:\/\/blog.sigfpe.com\/2007\/04\/trivial-monad.html\">this blog post<\/a>). The use of <span style=\"color: #00007f\">Identity<\/span> just fixes the \u2018impedance mismatch\u2019 between the function <span style=\"color: #00007f\">store<\/span>, which returns a pure value <span style=\"color: #00007f\">v<\/span>, and the <span style=\"color: #00007f\">fetch<\/span> argument of the <span style=\"color: #00007f\">task<\/span>, which must return an <span style=\"color: #00007f\">f v<\/span> for some <span style=\"color: #00007f\">f<\/span>. To fix the mismatch, we wrap the result of <span style=\"color: #00007f\">store<\/span> in the <span style=\"color: #00007f\">Identity\u00a0<\/span>monad: the function\u00a0<span style=\"color: #00007f\">Identity . store<\/span> has the type <span style=\"color: #00007f\">k \u2192 Identity v<\/span>, and can now be passed to a <span style=\"color: #00007f\">task<\/span>. The result comes as <span style=\"color: #00007f\">Maybe (Identity v)<\/span>, hence we now need to get rid of the <span style=\"color: #00007f\">Identity<\/span> wrapper by applying <span style=\"color: #00007f\">runIdentity<\/span> to the contents of <span style=\"color: #00007f\">Maybe<\/span>.<\/p>\n<p>In the GHCi session below we define a pure key\/value store with <span style=\"color: #00007f\">A1<\/span> set to <span style=\"color: #00007f\">10<\/span> and all other keys set to <span style=\"color: #00007f\">20<\/span> and compute the values corresponding to keys <span style=\"color: #00007f\">A1<\/span> and <span style=\"color: #00007f\">B1<\/span> in the\u00a0<span style=\"color: #00007f\">sprsh1<\/span> example:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\">\u03bb<span style=\"color: #794938\">&gt;<\/span> store key <span style=\"color: #794938\">=<\/span> <span style=\"color: #794938\">if<\/span> key <span style=\"color: #794938\">==<\/span> <span style=\"color: #0b6125\">\"A1\"<\/span> <span style=\"color: #794938\">then<\/span> <span style=\"color: #811f24;font-weight: bold\">10<\/span> <span style=\"color: #794938\">else<\/span> <span style=\"color: #811f24;font-weight: bold\">20<\/span>\r\n\u03bb<span style=\"color: #794938\">&gt;<\/span> compute sprsh1 store <span style=\"color: #0b6125\">\"A1\"<\/span>\r\n<span style=\"color: #b4371f\">Nothing<\/span>\r\n\r\n\u03bb<span style=\"color: #794938\">&gt;<\/span> compute sprsh1 store <span style=\"color: #0b6125\">\"B1\"<\/span>\r\n<span style=\"color: #b4371f\">Just<\/span> <span style=\"color: #811f24;font-weight: bold\">30<\/span>\r\n<\/pre>\n<p>As expected, we get\u00a0<span style=\"color: #00007f\">Nothing<\/span> for an input key\u00a0<span style=\"color: #00007f\">A1<\/span>\u00a0and <span style=\"color: #00007f\">Just 30<\/span>\u00a0for <span style=\"color: #00007f\">B1<\/span>.<\/p>\n<p>Notice that, even though <span style=\"color: #00007f\">compute<\/span> takes a <span style=\"color: #00007f\">Task Monad<\/span> as its argument, its application to a <span style=\"color: #00007f\">Task Applicative<\/span> typechecks just fine. It feels a bit like sub-typing, but is actually just ordinary <a href=\"https:\/\/www.microsoft.com\/en-us\/research\/publication\/practical-type-inference-for-arbitrary-rank-types\/\">higher-rank polymorphism<\/a>.<\/p>\n<p>Now let&#8217;s look at a function that can only be applied to applicative tasks.<\/p>\n<h3>Static dependencies<\/h3>\n<p>The formula <span style=\"color: #00007f\">A1 + A2<\/span> in the <span style=\"color: #00007f\">sprsh1<\/span> example statically depends on two keys: <span style=\"color: #00007f\">A1<\/span> and <span style=\"color: #00007f\">A2<\/span>.\u00a0Usually we would extract such static dependencies by looking at the syntax tree of the formula. But our\u00a0<span style=\"color: #00007f\">Task<\/span>\u00a0abstraction has no such syntax tree. Yet, remarkably, we can use the polymorphism of a <span style=\"color: #00007f\">Task Applicative<\/span> to find its dependencies. Here is the code:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><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\">Applicative<\/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>Here <span style=\"color: #00007f\">Const<\/span> is the standard Haskell <a href=\"https:\/\/hackage.haskell.org\/package\/base\/docs\/Data-Functor-Const.html\">Const functor<\/a>. We instantiate <span style=\"color: #00007f\">f<\/span> to <span style=\"color: #00007f\">Const [k]<\/span>. So a value of type <span style=\"color: #00007f\">f v<\/span>, or in this case <span style=\"color: #00007f\">Const [k] v<\/span>, contains no value <span style=\"color: #00007f\">v<\/span>, but does contain a list of keys of type <span style=\"color: #00007f\">[k]<\/span> which we use to record dependencies. The <span style=\"color: #00007f\">fetch<\/span> callback that we pass to <span style=\"color: #00007f\">task<\/span> records a single dependency, and the standard\u00a0<span style=\"color: #00007f\">Applicative<\/span>\u00a0instance for <span style=\"color: #00007f\">Const<\/span> combines the dependencies from different parts of the task. Running the task with <span style=\"color: #00007f\">f = Const [k]<\/span> will thus accumulate a list of the task\u2019s dependencies \u2013 and that is just what <span style=\"color: #00007f\">dependencies<\/span> does:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\">\u03bb<span style=\"color: #794938\">&gt;<\/span> dependencies sprsh1 <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> dependencies sprsh1 <span style=\"color: #0b6125\">\"B1\"<\/span>\r\n[<span style=\"color: #0b6125\">\"A1\"<\/span><span style=\"color: #794938\">,<\/span> <span style=\"color: #0b6125\">\"A2\"<\/span>]\r\n<\/pre>\n<p>Notice that these calls to <span style=\"color: #00007f\">dependencies<\/span> do no actual computation. They cannot: we are not supplying any input values. So, through the wonders of polymorphism, we are able to extract the dependencies of the spreadsheet formula, and to do so efficiently, simply by running its code in a different <span style=\"color: #00007f\">Applicative<\/span>! This is not new, for example see <a href=\"https:\/\/arxiv.org\/abs\/1403.0749\">this paper<\/a>, but it is cool.<\/p>\n<h3>Dynamic dependencies<\/h3>\n<p>Some build tasks have <em>dynamic dependencies<\/em>, which are determined by values of intermediate computations. Such tasks correspond to the type <span style=\"color: #00007f\">Task Monad k v<\/span>. Consider this spreadsheet example:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\">A1: 10      B1: IF(C1=1,B2,A2)      C1: 1\r\nA2: 20      B2: IF(C1=1,A1,B1)\r\n<\/pre>\n<p>Note that <span style=\"color: #00007f\">B1<\/span> and <span style=\"color: #00007f\">B2<\/span> statically form a dependency cycle, but Excel (which uses dynamic dependencies) is perfectly happy. The diagram below illustrates how cyclic dependencies are resolved when <em>projecting<\/em> them on\u00a0conditions <span style=\"color: #00007f\">C1=1<\/span> and <span style=\"color: #00007f\">C1=2<\/span> (rectangles and\u00a0rounded rectangles denote inputs and outputs, respectively). Incidentally, my PhD thesis was about a mathematical model for such conditional dependency graphs, which was later developed into <a href=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/an-algebra-of-graphs\/\">an algebra of graphs<\/a>.<\/p>\n<p><a href=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/files\/2018\/03\/cyclic-dependencies-example.png\"><img loading=\"lazy\" decoding=\"async\" id=\"graph\" class=\"aligncenter size-full wp-image-767\" src=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/files\/2018\/03\/cyclic-dependencies-example.png\" alt=\"Cyclic dependencies example\" width=\"2400\" height=\"1646\" srcset=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/files\/2018\/03\/cyclic-dependencies-example.png 2400w, https:\/\/blogs.ncl.ac.uk\/andreymokhov\/files\/2018\/03\/cyclic-dependencies-example-300x206.png 300w, https:\/\/blogs.ncl.ac.uk\/andreymokhov\/files\/2018\/03\/cyclic-dependencies-example-768x527.png 768w, https:\/\/blogs.ncl.ac.uk\/andreymokhov\/files\/2018\/03\/cyclic-dependencies-example-1024x702.png 1024w\" sizes=\"auto, (max-width: 2400px) 100vw, 2400px\" \/><\/a><\/p>\n<p>We can express this spreadsheet using our task abstraction as:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #bf4f24\">sprsh2<\/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\nsprsh2 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\nsprsh2 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\nsprsh2 _     _    <span style=\"color: #794938\">=<\/span> <span style=\"color: #b4371f\">Nothing<\/span>\r\n<\/pre>\n<p>The big difference compared to <span style=\"color: #00007f\">sprsh1<\/span> is that the computation now takes place in a <span style=\"color: #00007f\">Monad<\/span>, which allows us to extract the value of <span style=\"color: #00007f\">C1<\/span> and fetch <em>different keys depending on whether or not<\/em> <span style=\"color: #00007f\">C1 = 1<\/span>.<\/p>\n<p>We cannot find dependencies of monadic tasks statically; notice that the application of the function <span style=\"color: #00007f\">dependencies<\/span> to <span style=\"color: #00007f\">sprsh2<\/span> will not typecheck. We need to run a monadic task with concrete values that will determine the discovered dependencies. Thus, we introduce the function <span style=\"color: #00007f\">track<\/span>: a combination of <span style=\"color: #00007f\">compute<\/span> and <span style=\"color: #00007f\">dependencies\u00a0<\/span>that computes both the resulting value and the list of its dependencies in an arbitrary monadic context <span style=\"color: #00007f\">m<\/span>:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #bf4f24\">track<\/span> <span style=\"color: #794938\">::<\/span> <span style=\"color: #a71d5d;font-style: italic\">Monad<\/span> <span style=\"color: #234a97\">m<\/span> <span style=\"color: #794938\">=&gt;<\/span>\r\n         <span style=\"color: #811f24;font-weight: bold\">Task<\/span> <span style=\"color: #811f24;font-weight: bold\">Monad<\/span> k v <span style=\"color: #794938\">-&gt;<\/span> (k <span style=\"color: #794938\">-&gt;<\/span> m v) <span style=\"color: #794938\">-&gt;<\/span> k <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #811f24;font-weight: bold\">Maybe<\/span> (m (v<span style=\"color: #794938\">,<\/span> [k]))\r\ntrack task fetch <span style=\"color: #794938\">=<\/span> <span style=\"color: #693a17\">fmap<\/span> runWriterT <span style=\"color: #794938\">.<\/span> task trackingFetch\r\n  <span style=\"color: #794938\">where<\/span>\r\n    <span style=\"color: #bf4f24\">trackingFetch<\/span> <span style=\"color: #794938\">::<\/span> <span style=\"color: #234a97\">k<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #a71d5d;font-style: italic\">WriterT<\/span> [<span style=\"color: #234a97\">k<\/span>] <span style=\"color: #234a97\">m<\/span> <span style=\"color: #234a97\">v<\/span>\r\n    trackingFetch k <span style=\"color: #794938\">=<\/span> tell [k] <span style=\"color: #794938\">&gt;&gt;<\/span> lift (fetch k)\r\n<\/pre>\n<p>We use the standard<sup>(*)<\/sup>\u00a0Haskell <a href=\"https:\/\/hackage.haskell.org\/package\/mtl\/docs\/Control-Monad-Writer-Lazy.html\">WriterT\u00a0monad transformer<\/a>\u00a0to record additional information &#8212; a list of keys\u00a0<span style=\"color: #00007f\">[k]<\/span> &#8212; when computing a task in an arbitrary monad <span style=\"color: #00007f\">m<\/span>. We substitute the given <span style=\"color: #00007f\">fetch<\/span> with a <span style=\"color: #00007f\">trackingFetch<\/span> that, in addition to fetching a value, tracks the corresponding key. The <span style=\"color: #00007f\">task<\/span> returns the value of type <span style=\"color: #00007f\">Maybe (WriterT [k] m v)<\/span>, which we unwrap by applying <span style=\"color: #00007f\">runWriterT<\/span> to the contents of <span style=\"color: #00007f\">Maybe<\/span>. Below we give an example of <span style=\"color: #00007f\">track<\/span>ing monadic tasks when <span style=\"color: #00007f\">m = IO<\/span>:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\">\u03bb<span style=\"color: #794938\">&gt;<\/span> fetchIO k <span style=\"color: #794938\">=<\/span> <span style=\"color: #794938\">do<\/span> <span style=\"color: #693a17\">putStr<\/span> (k <span style=\"color: #794938\">++<\/span> <span style=\"color: #0b6125\">\": \"<\/span>); <span style=\"color: #693a17\">read<\/span> <span style=\"color: #794938\">&lt;$&gt;<\/span> <span style=\"color: #693a17\">getLine<\/span>\r\n\u03bb<span style=\"color: #794938\">&gt;<\/span> fromJust <span style=\"color: #794938\">$<\/span> track sprsh2 fetchIO <span style=\"color: #0b6125\">\"B1\"<\/span>\r\n<span style=\"color: #811f24;font-weight: bold\">C1<\/span><span style=\"color: #794938\">:<\/span> <span style=\"color: #811f24;font-weight: bold\">1<\/span>\r\n<span style=\"color: #811f24;font-weight: bold\">B2<\/span><span style=\"color: #794938\">:<\/span> <span style=\"color: #811f24;font-weight: bold\">10<\/span>\r\n(<span style=\"color: #811f24;font-weight: bold\">10<\/span><span style=\"color: #794938\">,<\/span>[<span style=\"color: #0b6125\">\"C1\"<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #0b6125\">\"B2\"<\/span>])\r\n\r\n\u03bb<span style=\"color: #794938\">&gt;<\/span> fromJust <span style=\"color: #794938\">$<\/span> track sprsh2 fetchIO <span style=\"color: #0b6125\">\"B1\"<\/span>\r\n<span style=\"color: #811f24;font-weight: bold\">C1<\/span><span style=\"color: #794938\">:<\/span> <span style=\"color: #811f24;font-weight: bold\">2<\/span>\r\n<span style=\"color: #811f24;font-weight: bold\">A2<\/span><span style=\"color: #794938\">:<\/span> <span style=\"color: #811f24;font-weight: bold\">20<\/span>\r\n(<span style=\"color: #811f24;font-weight: bold\">20<\/span><span style=\"color: #794938\">,<\/span>[<span style=\"color: #0b6125\">\"C1\"<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #0b6125\">\"A2\"<\/span>])\r\n<\/pre>\n<p>As expected, the dependencies of cell <span style=\"color: #00007f\">B1<\/span> from <span style=\"color: #00007f\">sprsh2<\/span> are determined by the value of <span style=\"color: #00007f\">C1<\/span>, which in this case is obtained by reading from the standard input via the\u00a0<span style=\"color: #00007f\">fetchIO<\/span> callback.<\/p>\n<h3>A simple build system<\/h3>\n<p>Given a task description, a target key, and a store, a <em>build system<\/em> returns a new store in which the values of the target key and all its dependencies are\u00a0up to date. What does &#8220;up to date&#8221; mean? The paper answers that in a formal way.<\/p>\n<p>The three functions described above (<span style=\"color: #00007f\">compute<\/span>, <span style=\"color: #00007f\">dependencies<\/span> and <span style=\"color: #00007f\">track<\/span>) are sufficient for defining the correctness of build systems as well as for implementing a few existing build systems at a conceptual level. Below is an example of a very simple (but inefficient) build system:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #bf4f24\">busy<\/span> <span style=\"color: #794938\">::<\/span> <span style=\"color: #a71d5d;font-style: italic\">Eq<\/span> <span style=\"color: #234a97\">k<\/span> <span style=\"color: #794938\">=&gt;<\/span> <span style=\"color: #a71d5d;font-style: italic\">Task<\/span> <span style=\"color: #a71d5d;font-style: italic\">Monad<\/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: #a71d5d;font-style: italic\">Store<\/span> <span style=\"color: #234a97\">k<\/span> <span style=\"color: #234a97\">v<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #a71d5d;font-style: italic\">Store<\/span> <span style=\"color: #234a97\">k<\/span> <span style=\"color: #234a97\">v<\/span>\r\nbusy task key store <span style=\"color: #794938\">=<\/span> execState (fetch key) store\r\n  <span style=\"color: #794938\">where<\/span>\r\n    <span style=\"color: #bf4f24\">fetch<\/span> <span style=\"color: #794938\">::<\/span> <span style=\"color: #234a97\">k<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #a71d5d;font-style: italic\">State<\/span> (<span style=\"color: #a71d5d;font-style: italic\">Store<\/span> <span style=\"color: #234a97\">k<\/span> <span style=\"color: #234a97\">v<\/span>) <span style=\"color: #234a97\">v<\/span>\r\n    fetch k <span style=\"color: #794938\">=<\/span> <span style=\"color: #794938\">case<\/span> task fetch k <span style=\"color: #794938\">of<\/span>\r\n        <span style=\"color: #b4371f\">Nothing<\/span>  <span style=\"color: #794938\">-&gt;<\/span> gets (getValue k)\r\n        <span style=\"color: #b4371f\">Just<\/span> act <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #794938\">do<\/span> v <span style=\"color: #794938\">&lt;-<\/span> act; modify (putValue k v); <span style=\"color: #693a17\">return<\/span> v\r\n<\/pre>\n<p>Here <span style=\"color: #00007f\">Store k v<\/span> is an abstract store datatype equipped with <span style=\"color: #00007f\">getValue<\/span> and <span style=\"color: #00007f\">setValue<\/span> functions.\u00a0The <span style=\"color: #00007f\">busy<\/span> build system defines the callback <span style=\"color: #00007f\">fetch<\/span> so that, when given a target <span style=\"color: #00007f\">key<\/span>, it brings the key up to date in the store, and returns its value. The function <span style=\"color: #00007f\">fetch<\/span> runs in the standard Haskell <a href=\"https:\/\/hackage.haskell.org\/package\/mtl\/docs\/Control-Monad-State-Lazy.html\">State monad<\/a>, initialised with the incoming <span style=\"color: #00007f\">store<\/span> by <span style=\"color: #00007f\">execState<\/span>. To bring a key <span style=\"color: #00007f\">k<\/span> up to date, <span style=\"color: #00007f\">fetch<\/span> asks the task description <span style=\"color: #00007f\">task<\/span> how to compute <span style=\"color: #00007f\">k<\/span>. If <span style=\"color: #00007f\">task<\/span> returns <span style=\"color: #00007f\">Nothing<\/span> the key is an input, so <span style=\"color: #00007f\">fetch<\/span> simply reads the result from the store. Otherwise <span style=\"color: #00007f\">fetch<\/span> runs the action <span style=\"color: #00007f\">act<\/span> returned by the task to produce a resulting value <span style=\"color: #00007f\">v<\/span>, records the new key\/value mapping in the store, and returns <span style=\"color: #00007f\">v<\/span>. Notice that <span style=\"color: #00007f\">fetch<\/span> passes itself to <span style=\"color: #00007f\">task<\/span> as an argument, so that the latter can use <span style=\"color: #00007f\">fetch<\/span> to recursively find the values of <span style=\"color: #00007f\">k<\/span>&#8216;s dependencies.<\/p>\n<p>Given an acyclic task description, the <span style=\"color: #00007f\">busy<\/span> build system terminates with a correct result, but it is not a <em>minimal<\/em> build system:\u00a0it doesn&#8217;t keep track of keys it has already built, and will therefore busily recompute the same keys again and again if they have multiple dependants. See the paper for implementations of much more efficient build systems.<\/p>\n<h3>For a few monads more<\/h3>\n<p>We have already used a few cool Haskell types &#8212;\u00a0<span style=\"color: #00007f\">Identity<\/span>, <span style=\"color: #00007f\">Const<\/span>, <span style=\"color: #00007f\">WriterT<\/span> and <span style=\"color: #00007f\">State\u00a0<\/span>&#8212; to manipulate our <span style=\"color: #00007f\">Task<\/span> abstraction. Let&#8217;s meet a few other members of the cool-types family:\u00a0<span style=\"color: #00007f\">Proxy<\/span>, <span style=\"color: #00007f\">ReaderT<\/span>, <span style=\"color: #00007f\">MaybeT<\/span> and\u00a0<span style=\"color: #00007f\">EitherT<\/span>.<\/p>\n<p>The <a href=\"https:\/\/hackage.haskell.org\/package\/base\/docs\/Data-Proxy.html\">Proxy data type<\/a> allows us to check whether a key is an input without providing a <span style=\"color: #00007f\">fetch<\/span> callback:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #bf4f24\">isInput<\/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: #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: #691c97\">Bool<\/span>\r\nisInput task <span style=\"color: #794938\">=<\/span> isNothing <span style=\"color: #794938\">.<\/span> task (<span style=\"color: #693a17\">const<\/span> <span style=\"color: #811f24;font-weight: bold\">Proxy<\/span>)\r\n<\/pre>\n<p>This works similarly to the <span style=\"color: #00007f\">dependencies<\/span> function, but in this case we do not even need to record any additional information, thus we can replace <span style=\"color: #00007f\">Const<\/span> with <span style=\"color: #00007f\">Proxy<\/span>.<\/p>\n<p>One might wonder: if we do not need the <span style=\"color: #00007f\">fetch<\/span> callback in case of input, can we rewrite our Task abstraction as follows?<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #794938\">type<\/span> <span style=\"color: #811f24;font-weight: bold\">Task2<\/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> <span style=\"color: #811f24;font-weight: bold\">Maybe<\/span> ((k <span style=\"color: #794938\">-&gt;<\/span> f v) <span style=\"color: #794938\">-&gt;<\/span> f v)\r\n<\/pre>\n<p>Yes, we can! This definition is\u00a0isomorphic to <span style=\"color: #00007f\">Task<\/span>. This isn&#8217;t immediately obvious, so below is a proof. I confess: it took me a while to find it.<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #bf4f24\">toTask<\/span> <span style=\"color: #794938\">::<\/span> <span style=\"color: #a71d5d;font-style: italic\">Task2<\/span> <span style=\"color: #a71d5d;font-style: italic\">Monad<\/span> <span style=\"color: #234a97\">k<\/span> <span style=\"color: #234a97\">v<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #a71d5d;font-style: italic\">Task<\/span> <span style=\"color: #a71d5d;font-style: italic\">Monad<\/span> <span style=\"color: #234a97\">k<\/span> <span style=\"color: #234a97\">v<\/span>\r\ntoTask task2 fetch key <span style=\"color: #794938\">=<\/span> (<span style=\"color: #794938\">$<\/span>fetch) <span style=\"color: #794938\">&lt;$&gt;<\/span> task2 key\r\n\r\n<span style=\"color: #bf4f24\">fromTask<\/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: #234a97\">k<\/span> <span style=\"color: #234a97\">v<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #a71d5d;font-style: italic\">Task2<\/span> <span style=\"color: #a71d5d;font-style: italic\">Monad<\/span> <span style=\"color: #234a97\">k<\/span> <span style=\"color: #234a97\">v<\/span>\r\nfromTask task key <span style=\"color: #794938\">=<\/span> runReaderT <span style=\"color: #794938\">&lt;$&gt;<\/span> task (<span style=\"color: #794938\">\\<\/span>k <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #811f24;font-weight: bold\">ReaderT<\/span> (<span style=\"color: #794938\">$<\/span>k)) key\r\n<\/pre>\n<p>The <span style=\"color: #00007f\">toTask<\/span>\u00a0conversion is relatively straightforward, but <span style=\"color: #00007f\">fromTask<\/span>\u00a0is not: it uses a <a href=\"https:\/\/hackage.haskell.org\/package\/mtl\/docs\/Control-Monad-Reader.html\">ReaderT monad transformer<\/a> to supply the <span style=\"color: #00007f\">fetch<\/span> callback as the computation environment, extracting the final value with\u00a0<span style=\"color: #00007f\">runReaderT<\/span>.<\/p>\n<p>Our task abstraction operates on pure values and has no mechanism for exception handling. It turns out that it is easy to turn any <span style=\"color: #00007f\">Task<\/span> into a task that can handle arbitrary exceptions occurring in the <span style=\"color: #00007f\">fetch<\/span> callback:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #bf4f24\">exceptional<\/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: #234a97\">k<\/span> <span style=\"color: #234a97\">v<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #a71d5d;font-style: italic\">Task<\/span> <span style=\"color: #a71d5d;font-style: italic\">Monad<\/span> <span style=\"color: #234a97\">k<\/span> (<span style=\"color: #691c97\">Either<\/span> <span style=\"color: #234a97\">e<\/span> <span style=\"color: #234a97\">v<\/span>)\r\nexceptional task fetch <span style=\"color: #794938\">=<\/span> <span style=\"color: #693a17\">fmap<\/span> runExceptT <span style=\"color: #794938\">.<\/span> task (<span style=\"color: #811f24;font-weight: bold\">ExceptT<\/span> <span style=\"color: #794938\">.<\/span> fetch)\r\n<\/pre>\n<p>The <span style=\"color: #00007f\">exceptional<\/span> <em>task transformer<\/em>\u00a0simply hides exceptions of the given <span style=\"color: #00007f\">fetch<\/span>\u00a0of type <span style=\"color: #00007f\">k \u2192 f (Either e v)<\/span> by using the standard <a href=\"https:\/\/hackage.haskell.org\/package\/transformers\/docs\/Control-Monad-Trans-Except.html\">ExceptT monad transformer<\/a>, passes the resulting fetch callback of type\u00a0<span style=\"color: #00007f\">k \u2192 ExceptT e f v<\/span> to the original <span style=\"color: #00007f\">task<\/span>, and propagates the exceptions by\u00a0<span style=\"color: #00007f\">runExceptT<\/span>. Using <a href=\"https:\/\/hackage.haskell.org\/package\/transformers\/docs\/Control-Monad-Trans-Maybe.html\">MaybeT<\/a>, one can also implement a similar\u00a0task transformer that turns a <span style=\"color: #00007f\">Task Monad k v<\/span> into the its partial version\u00a0<span style=\"color: #00007f\">Task Monad k (Maybe v)<\/span>.<\/p>\n<p>Our final exercise is to extract all possible computation results of a <em>non-deterministic task<\/em>, e.g.\u00a0<span style=\"color: #00007f\">B1 = A1 + RANDBETWEEN(1,2) <\/span>that can be described as a <span style=\"color: #00007f\">Task Alternative<\/span>:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808;padding-left: 7pt;padding-right: 7pt\"><span style=\"color: #bf4f24\">sprsh3<\/span> <span style=\"color: #794938\">::<\/span> <span style=\"color: #a71d5d;font-style: italic\">Task<\/span> <span style=\"color: #a71d5d;font-style: italic\">Alternative<\/span> <span style=\"color: #691c97\">String<\/span> <span style=\"color: #691c97\">Integer<\/span>\r\nsprsh3 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: #bf4f24\">(+)<\/span> <span style=\"color: #794938\">&lt;$&gt;<\/span> fetch <span style=\"color: #0b6125\">\"A1\"<\/span> <span style=\"color: #794938\">&lt;<\/span>*<span style=\"color: #794938\">&gt;<\/span> (pure <span style=\"color: #811f24;font-weight: bold\">1<\/span> <span style=\"color: #794938\">&lt;|&gt;<\/span> pure <span style=\"color: #811f24;font-weight: bold\">2<\/span>)\r\nsprsh3 _     _    <span style=\"color: #794938\">=<\/span> <span style=\"color: #b4371f\">Nothing<\/span>\r\n<\/pre>\n<p>We therefore introduce the function <span style=\"color: #00007f\">computeND<\/span> that returns the list of all possible results of the task instead of just one value (\u2018ND\u2019 stands for \u2018non-deterministic\u2019):<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #bf4f24\">computeND<\/span> <span style=\"color: #794938\">::<\/span> <span style=\"color: #a71d5d;font-style: italic\">Task<\/span> <span style=\"color: #a71d5d;font-style: italic\">MonadPlus<\/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\">v<\/span>) <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #234a97\">k<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #691c97\">Maybe<\/span> [<span style=\"color: #234a97\">v<\/span>]\r\ncomputeND task store <span style=\"color: #794938\">=<\/span> task (<span style=\"color: #693a17\">return<\/span> <span style=\"color: #794938\">.<\/span> store)\r\n<\/pre>\n<p>The implementation is almost straightforward: we choose <span style=\"color: #00007f\">f = []<\/span> reusing the standard <span style=\"color: #00007f\">MonadPlus<\/span> instance for lists. Let&#8217;s give it a try:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\">\u03bb<span style=\"color: #794938\">&gt;<\/span> store key <span style=\"color: #794938\">=<\/span> <span style=\"color: #794938\">if<\/span> key <span style=\"color: #794938\">==<\/span> <span style=\"color: #0b6125\">\"A1\"<\/span> <span style=\"color: #794938\">then<\/span> <span style=\"color: #811f24;font-weight: bold\">10<\/span> <span style=\"color: #794938\">else<\/span> <span style=\"color: #811f24;font-weight: bold\">20<\/span>\r\n\u03bb<span style=\"color: #794938\">&gt;<\/span> computeND sprsh3 store <span style=\"color: #0b6125\">\"A1\"<\/span>\r\n<span style=\"color: #b4371f\">Nothing<\/span>\r\n\r\n\u03bb<span style=\"color: #794938\">&gt;<\/span> computeND sprsh3 store <span style=\"color: #0b6125\">\"B1\"<\/span>\r\n<span style=\"color: #b4371f\">Just<\/span> [<span style=\"color: #811f24;font-weight: bold\">11<\/span><span style=\"color: #794938\">,<\/span><span style=\"color: #811f24;font-weight: bold\">12<\/span>]\r\n\r\n\u03bb<span style=\"color: #794938\">&gt;<\/span> computeND sprsh1 store <span style=\"color: #0b6125\">\"B1\"<\/span>\r\n<span style=\"color: #b4371f\">Just<\/span> [<span style=\"color: #811f24;font-weight: bold\">30<\/span>]\r\n<\/pre>\n<p>Notice that we can apply\u00a0<span style=\"color: #00007f\">computeND<\/span> to both non-deterministic (<span style=\"color: #00007f\">sprsh3<\/span>) as well as deterministic (<span style=\"color: #00007f\">sprsh1<\/span>) task descriptions.<\/p>\n<p>Non-deterministic tasks are interesting because they allow one to try different algorithms to compute a value in parallel and grab the first available result &#8212; a good example is\u00a0<a href=\"https:\/\/arxiv.org\/abs\/1505.03340\">portfolio-based parallel SAT solvers<\/a>. This shouldn&#8217;t be confused with a <em>deterministic composition<\/em> of tasks, which is also a useful operation, but does not involve any non-determinism:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #bf4f24\">compose<\/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: #234a97\">k<\/span> <span style=\"color: #234a97\">v<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #a71d5d;font-style: italic\">Task<\/span> <span style=\"color: #a71d5d;font-style: italic\">Monad<\/span> <span style=\"color: #234a97\">k<\/span> <span style=\"color: #234a97\">v<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #a71d5d;font-style: italic\">Task<\/span> <span style=\"color: #a71d5d;font-style: italic\">Monad<\/span> <span style=\"color: #234a97\">k<\/span> <span style=\"color: #234a97\">v<\/span>\r\ncompose t1 t2 fetch key <span style=\"color: #794938\">=<\/span> t1 fetch key <span style=\"color: #794938\">&lt;|&gt;<\/span> t2 fetch key\r\n<\/pre>\n<p>Here we simply compose two task descriptions, picking the first one that knows how to compute a given <span style=\"color: #00007f\">key<\/span>. Together with the trivial task that returns <span style=\"color: #00007f\">Nothing<\/span> for all keys, this gives rise to the <span style=\"color: #00007f\">Task<\/span> monoid.<\/p>\n<h3>Final remarks<\/h3>\n<p>We introduced the task abstraction to study build systems, but it seems to be linked to a few other topics, such as <a href=\"https:\/\/wiki.haskell.org\/Memoization\">memoization<\/a>, <a href=\"http:\/\/www.umut-acar.org\/self-adjusting-computation\">self-adjusting computation<\/a>, <a href=\"https:\/\/hackage.haskell.org\/package\/lens\">lenses<\/a> and <a href=\"https:\/\/arxiv.org\/abs\/1703.10857\">profunctor optics<\/a>, <a href=\"https:\/\/qfpl.io\/share\/talks\/propagators\/slides.pdf\">propagators<\/a>\u00a0and what not.<\/p>\n<p>Have we just reinvented the wheel? It might seem so, especially if you look at these <a href=\"https:\/\/hackage.haskell.org\/package\/lens-4.16.1\/docs\/Control-Lens-Type.html#t:Lens\">type<\/a> <a href=\"https:\/\/hackage.haskell.org\/package\/lens-4.16.1\/docs\/Control-Lens-Type.html#t:Traversal\">signatures<\/a> from the <span style=\"color: #00007f\">lens<\/span> library:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #794938\">type<\/span> <span style=\"color: #811f24;font-weight: bold\">Lens<\/span> s t a b\r\n    <span style=\"color: #794938\">=<\/span> forall f<span style=\"color: #794938\">.<\/span> <span style=\"color: #811f24;font-weight: bold\">Functor<\/span> f <span style=\"color: #794938\">=&gt;<\/span> (a <span style=\"color: #794938\">-&gt;<\/span> f b) <span style=\"color: #794938\">-&gt;<\/span> s <span style=\"color: #794938\">-&gt;<\/span> f t\r\n\r\n<span style=\"color: #794938\">type<\/span> <span style=\"color: #811f24;font-weight: bold\">Traversal<\/span> s t a b\r\n    <span style=\"color: #794938\">=<\/span> forall f<span style=\"color: #794938\">.<\/span> <span style=\"color: #811f24;font-weight: bold\">Applicative<\/span> f <span style=\"color: #794938\">=&gt;<\/span> (a <span style=\"color: #794938\">-&gt;<\/span> f b) <span style=\"color: #794938\">-&gt;<\/span> s <span style=\"color: #794938\">-&gt;<\/span> f t\r\n<\/pre>\n<p>Our implementations of functions like <span style=\"color: #00007f\">dependencies<\/span> are heavily inspired by &#8212; or to be more accurate &#8212; stolen from the <span style=\"color: #00007f\">lens<\/span> library. Alas, we have been unable to remove the <span style=\"color: #00007f\">Maybe<\/span> used to encode whether a key is an input, without complicating other aspects of our definition.<\/p>\n<p>The task abstraction can be used to express pure functions in a way that is convenient for their memoization. Here is an example of encoding <a href=\"https:\/\/twitter.com\/i\/moments\/976228768221102087\">one of the most favourite functions<\/a> of functional programmers:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #bf4f24\">fibonacci<\/span> <span style=\"color: #794938\">::<\/span> <span style=\"color: #a71d5d;font-style: italic\">Task<\/span> <span style=\"color: #a71d5d;font-style: italic\">Applicative<\/span> <span style=\"color: #691c97\">Integer<\/span> <span style=\"color: #691c97\">Integer<\/span>\r\nfibonacci fetch n\r\n    <span style=\"color: #794938\">|<\/span> n <span style=\"color: #794938\">&gt;=<\/span> <span style=\"color: #811f24;font-weight: bold\">2<\/span> <span style=\"color: #794938\">=<\/span> <span style=\"color: #b4371f\">Just<\/span> <span style=\"color: #794938\">$<\/span> <span style=\"color: #bf4f24\">(+)<\/span> <span style=\"color: #794938\">&lt;$&gt;<\/span> fetch (n<span style=\"color: #794938\">-<\/span><span style=\"color: #811f24;font-weight: bold\">1<\/span>) <span style=\"color: #794938\">&lt;<\/span>*<span style=\"color: #794938\">&gt;<\/span> fetch (n<span style=\"color: #794938\">-<\/span><span style=\"color: #811f24;font-weight: bold\">2<\/span>)\r\n    <span style=\"color: #794938\">|<\/span> <span style=\"color: #693a17\">otherwise<\/span> <span style=\"color: #794938\">=<\/span> <span style=\"color: #b4371f\">Nothing<\/span>\r\n<\/pre>\n<p>Here the keys\u00a0<span style=\"color: #00007f\">n &lt; 2<\/span> are input parameters, and one can obtain the usual Fibonacci sequence by picking\u00a0<span style=\"color: #00007f\">0<\/span> and <span style=\"color: #00007f\">1<\/span> for <span style=\"color: #00007f\">n = 0<\/span> and <span style=\"color: #00007f\">n = 1<\/span>, respectively. Any minimal build system will compute the sequence with memoization, i.e. without recomputing the same value twice.<\/p>\n<p>Interestingly, the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Ackermann_function\">Ackermann function<\/a>\u00a0&#8212; a famous example of a function that is not primitive recursive &#8212; can&#8217;t be expressed as a <span style=\"color: #00007f\">Task Applicative<\/span>, since it needs to perform an intermediate recursive call to determine one of its dependencies:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #bf4f24\">ackermann<\/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\">Integer<\/span>, <span style=\"color: #691c97\">Integer<\/span>) <span style=\"color: #691c97\">Integer<\/span>\r\nackermann fetch (n<span style=\"color: #794938\">,<\/span> m)\r\n    <span style=\"color: #794938\">|<\/span> m <span style=\"color: #794938\">&lt;<\/span> <span style=\"color: #811f24;font-weight: bold\">0<\/span> <span style=\"color: #794938\">||<\/span> n <span style=\"color: #794938\">&lt;<\/span> <span style=\"color: #811f24;font-weight: bold\">0<\/span> <span style=\"color: #794938\">=<\/span> <span style=\"color: #b4371f\">Nothing<\/span>\r\n    <span style=\"color: #794938\">|<\/span> m <span style=\"color: #794938\">==<\/span> <span style=\"color: #811f24;font-weight: bold\">0<\/span>    <span style=\"color: #794938\">=<\/span> <span style=\"color: #b4371f\">Just<\/span> <span style=\"color: #794938\">$<\/span> pure (n <span style=\"color: #794938\">+<\/span> <span style=\"color: #811f24;font-weight: bold\">1<\/span>)\r\n    <span style=\"color: #794938\">|<\/span> n <span style=\"color: #794938\">==<\/span> <span style=\"color: #811f24;font-weight: bold\">0<\/span>    <span style=\"color: #794938\">=<\/span> <span style=\"color: #b4371f\">Just<\/span> <span style=\"color: #794938\">$<\/span> fetch (m <span style=\"color: #794938\">-<\/span> <span style=\"color: #811f24;font-weight: bold\">1<\/span><span style=\"color: #794938\">,<\/span> <span style=\"color: #811f24;font-weight: bold\">1<\/span>)\r\n    <span style=\"color: #794938\">|<\/span> <span style=\"color: #693a17\">otherwise<\/span> <span style=\"color: #794938\">=<\/span> <span style=\"color: #b4371f\">Just<\/span> <span style=\"color: #794938\">$<\/span> <span style=\"color: #794938\">do<\/span> index <span style=\"color: #794938\">&lt;-<\/span> fetch (m<span style=\"color: #794938\">,<\/span> n <span style=\"color: #794938\">-<\/span> <span style=\"color: #811f24;font-weight: bold\">1<\/span>)\r\n                            fetch (m <span style=\"color: #794938\">-<\/span> <span style=\"color: #811f24;font-weight: bold\">1<\/span><span style=\"color: #794938\">,<\/span> index)\r\n<\/pre>\n<p>Now that we&#8217;ve seen examples of applicative and monadic tasks, let us finish with an example of a functorial task &#8212; the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Collatz_conjecture\">Collatz sequence<\/a>:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #bf4f24\">collatz<\/span> <span style=\"color: #794938\">::<\/span> <span style=\"color: #a71d5d;font-style: italic\">Task<\/span> <span style=\"color: #a71d5d;font-style: italic\">Functor<\/span> <span style=\"color: #691c97\">Integer<\/span> <span style=\"color: #691c97\">Integer<\/span>\r\ncollatz fetch n <span style=\"color: #794938\">|<\/span> n <span style=\"color: #794938\">&lt;=<\/span> <span style=\"color: #811f24;font-weight: bold\">0<\/span>    <span style=\"color: #794938\">=<\/span> <span style=\"color: #b4371f\">Nothing<\/span>\r\n                <span style=\"color: #794938\">|<\/span> <span style=\"color: #693a17\">otherwise<\/span> <span style=\"color: #794938\">=<\/span> <span style=\"color: #b4371f\">Just<\/span> <span style=\"color: #794938\">$<\/span> f <span style=\"color: #794938\">&lt;$&gt;<\/span> fetch (n <span style=\"color: #794938\">-<\/span> <span style=\"color: #811f24;font-weight: bold\">1<\/span>)\r\n  <span style=\"color: #794938\">where<\/span>\r\n    f k <span style=\"color: #794938\">|<\/span> <span style=\"color: #693a17\">even<\/span> k    <span style=\"color: #794938\">=<\/span> k <span style=\"color: #794938\">`div`<\/span> <span style=\"color: #811f24;font-weight: bold\">2<\/span>\r\n        <span style=\"color: #794938\">|<\/span> <span style=\"color: #693a17\">otherwise<\/span> <span style=\"color: #794938\">=<\/span> <span style=\"color: #811f24;font-weight: bold\">3<\/span> * k <span style=\"color: #794938\">+<\/span> <span style=\"color: #811f24;font-weight: bold\">1<\/span>\r\n<\/pre>\n<p>So here is a claim: given a <span style=\"color: #00007f\">Task<\/span>, we can memoize, self-adjust, propagate and probably do any other conceivable computation on it simply by picking the right build system!<\/p>\n<h3>Update: how to handle failures<\/h3>\n<p>Sjoerd Visscher&#8217;s comment (below) pointed out that the <span style=\"color: #00007f\">fetch<\/span> callback is defined to be total: it has type <span style=\"color: #00007f\">k \u2192 f v<\/span> and returns a value for every key. It may be useful to allow it to fail for some keys. I know of three ways of modelling failure using the <span style=\"color: #00007f\">Task<\/span> abstraction:<\/p>\n<p>(1) Include failures into the type of values <span style=\"color: #00007f\">v<\/span>, for example:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #794938\">data<\/span> <span style=\"color: #811f24;font-weight: bold\">Value<\/span> <span style=\"color: #794938\">=<\/span> <span style=\"color: #811f24;font-weight: bold\">FileNotFound<\/span> <span style=\"color: #794938\">|<\/span> <span style=\"color: #811f24;font-weight: bold\">FileContents<\/span> <span style=\"color: #811f24;font-weight: bold\">ByteString<\/span>\r\n<\/pre>\n<p>This is convenient if\u00a0<em>tasks are aware of failures<\/em>. For example, a task may be able to cope with missing files, e.g. if <span style=\"color: #00007f\">fetch &#8220;username.txt&#8221;<\/span> returns <span style=\"color: #00007f\">FileNotFound<\/span>, the task could use the literal string <span style=\"color: #00007f\">&#8220;User&#8221;<\/span> as a default value. In this case it will depend on the fact that the file <span style=\"color: #00007f\">username.txt<\/span> is missing, and will need to be rebuilt if the user later creates this file.<\/p>\n<p>In many cases this approach is isomorphic to choosing <span style=\"color: #00007f\">v = Either e v&#8217;<\/span>.<\/p>\n<p>(2) Include failures into the computation context <span style=\"color: #00007f\">f<\/span>, for example:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #bf4f24\">cells<\/span> <span style=\"color: #794938\">::<\/span> <span style=\"color: #a71d5d;font-style: italic\">Map<\/span> <span style=\"color: #691c97\">String<\/span> <span style=\"color: #691c97\">Integer<\/span>\r\ncells <span style=\"color: #794938\">=<\/span> <span style=\"color: #811f24;font-weight: bold\">Map<\/span><span style=\"color: #794938\">.<\/span>fromList [(<span style=\"color: #0b6125\">\"A1\"<\/span><span style=\"color: #794938\">,<\/span> <span style=\"color: #811f24;font-weight: bold\">10<\/span>)<span style=\"color: #794938\">,<\/span> (<span style=\"color: #0b6125\">\"A2\"<\/span><span style=\"color: #794938\">,<\/span> <span style=\"color: #811f24;font-weight: bold\">20<\/span>)]\r\n\r\n<span style=\"color: #bf4f24\">fetch<\/span> <span style=\"color: #794938\">::<\/span> <span style=\"color: #691c97\">String<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #691c97\">Maybe<\/span> <span style=\"color: #691c97\">Integer<\/span>\r\nfetch k <span style=\"color: #794938\">=<\/span> <span style=\"color: #811f24;font-weight: bold\">Map<\/span><span style=\"color: #794938\">.<\/span><span style=\"color: #693a17\">lookup<\/span> k cells\r\n<\/pre>\n<p>We are choosing <span style=\"color: #00007f\">f = Maybe<\/span>\u00a0and thanks to the polymorphism of\u00a0<span style=\"color: #00007f\">Task,<\/span> any task can be executed in this context without any changes. For example,\u00a0 <span style=\"color: #00007f\">sprsh1 fetch &#8220;B1&#8221;<\/span> now returns <span style=\"color: #00007f\">Just (Just 30)<\/span>, but\u00a0<span style=\"color: #00007f\">sprsh1 fetch &#8220;B2&#8221;<\/span> fails with <span style=\"color: #00007f\">Just Nothing<\/span>.<\/p>\n<p>This is convenient if\u00a0<em>tasks are not aware of failures<\/em>, e.g. we can model Excel formulas as pure arithmetic functions, and introduce failures &#8220;for free&#8221; if\/when needed by instantiating <span style=\"color: #00007f\">Task<\/span> with an appropriate <span style=\"color: #00007f\">f<\/span>. Also see the function <span style=\"color: #00007f\">exceptional<\/span>\u00a0defined above, which allows us to add arbitrary exceptions to a failure-free context <span style=\"color: #00007f\">f<\/span>.<\/p>\n<p>(3)\u00a0Finally, the task itself might not want to encode failures into the type of values <span style=\"color: #00007f\">v<\/span>, but instead <em>demand that <span style=\"color: #00007f\">f<\/span> has a built-in notion of failures<\/em>. This can be done by choosing a suitable constraint <span style=\"color: #00007f\">c<\/span>, such as\u00a0<span style=\"color: #00007f\">Alternative<\/span>, <span style=\"color: #00007f\">MonadPlus<\/span> or even better something specific to failures e.g. <a href=\"https:\/\/wiki.haskell.org\/MonadPlus_reform_proposal\">MonadZero<\/a> or <a href=\"https:\/\/prime.haskell.org\/wiki\/Libraries\/Proposals\/MonadFail\">MonadFail<\/a>. Then both the callback and the task can reuse the same failure mechanism as shown below:<\/p>\n<pre style=\"background: #f9f9f9;color: #080808\"><span style=\"color: #794938\">class<\/span> <span style=\"color: #691c97\">Monad<\/span> <span style=\"color: #234a97\">m<\/span> =&gt; <span style=\"color: #bf4f24\">MonadFail<\/span> <span style=\"color: #234a97\">m<\/span> <span style=\"color: #794938\">where<\/span>\r\n    <span style=\"color: #bf4f24\">fail<\/span> <span style=\"color: #794938\">::<\/span> <span style=\"color: #691c97\">String<\/span> <span style=\"color: #794938\">-&gt;<\/span> <span style=\"color: #234a97\">m<\/span> <span style=\"color: #234a97\">a<\/span>\r\n\r\n<span style=\"color: #bf4f24\">sprsh4<\/span> <span style=\"color: #794938\">::<\/span> <span style=\"color: #a71d5d;font-style: italic\">Task<\/span> <span style=\"color: #a71d5d;font-style: italic\">MonadFail<\/span> <span style=\"color: #691c97\">String<\/span> <span style=\"color: #691c97\">Integer<\/span>\r\nsprsh4 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>\r\n    a1 <span style=\"color: #794938\">&lt;-<\/span> fetch <span style=\"color: #0b6125\">\"A1\"<\/span>\r\n    a2 <span style=\"color: #794938\">&lt;-<\/span> fetch <span style=\"color: #0b6125\">\"A2\"<\/span>\r\n    <span style=\"color: #794938\">if<\/span> a2 <span style=\"color: #794938\">==<\/span> <span style=\"color: #811f24;font-weight: bold\">0<\/span> <span style=\"color: #794938\">then<\/span> <span style=\"color: #693a17\">fail<\/span> <span style=\"color: #0b6125\">\"division by 0\"<\/span> <span style=\"color: #794938\">else<\/span> <span style=\"color: #693a17\">return<\/span> (a1 <span style=\"color: #794938\">`div`<\/span> a2)\r\nsprsh4 _ _ <span style=\"color: #794938\">=<\/span> <span style=\"color: #b4371f\">Nothing<\/span>\r\n<\/pre>\n<p>Are there any other types of failure that are not covered above?<\/p>\n<h5>Footnotes<\/h5>\n<p><sup>(*)<\/sup> Beware: as of writing, standard <span style=\"color: #00007f\">WriterT<\/span> transformers have a space leak which may be an issue if a task has many dependencies. You might want to consider using <a href=\"https:\/\/hackage.haskell.org\/package\/writer-cps-mtl\/docs\/Control-Monad-Writer-CPS.html\">a more efficient CPS-based WriterT transformer<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Neil Mitchell, Simon Peyton Jones and I have just finished a paper describing a systematic and executable framework for developing and comparing build systems. The paper and associated code are available here: https:\/\/github.com\/snowleopard\/build. The code is not yet well documented and polished, but I&#8217;ll bring it in a good shape in April. You can learn &hellip; <a href=\"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/the-task-abstraction\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">The Task abstraction<\/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,12],"tags":[4],"class_list":["post-671","post","type-post","status-publish","format-standard","hentry","category-coding","category-research","tag-haskell"],"_links":{"self":[{"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/posts\/671","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=671"}],"version-history":[{"count":108,"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/posts\/671\/revisions"}],"predecessor-version":[{"id":1131,"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/posts\/671\/revisions\/1131"}],"wp:attachment":[{"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/media?parent=671"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/categories?post=671"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.ncl.ac.uk\/andreymokhov\/wp-json\/wp\/v2\/tags?post=671"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}