Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Will this do?</p> <pre><code>flip . (evalState .) . traverse . traverse . const . state $ head &amp;&amp;&amp; tail </code></pre> <p>EDIT: let me expand on the construction...</p> <p>The essential centre of it is <code>traverse . traverse</code>. If you stare at the problem with sufficiently poor spectacles, you can see that it's "do something with the elements of a container of containers". For that sort of thing, <code>traverse</code> (from <code>Data.Traversable</code>) is a very useful gadget (ok, I'm biased).</p> <pre><code>traverse :: (Traversable f, Applicative a) =&gt; (s -&gt; a t) -&gt; f s -&gt; a (f t) </code></pre> <p>or, if I change to longer but more suggestive type variables</p> <pre><code>traverse :: (Traversable containerOf, Applicative doingSomethingToGet) =&gt; (s -&gt; doingSomethingToGet t) -&gt; containerOf s -&gt; doingSomethingToGet (containerOf t) </code></pre> <p>Crucially, <code>traverse</code> preserves the structure of the container it operates on, whatever that might be. If you view <code>traverse</code> as a higher-order function, you can see that it gives back an operator on containers whose type fits with the type of operators on elements it demands. That's to say <code>(traverse . traverse)</code> makes sense, and gives you structure-preserving operations on <em>two</em> layers of container.</p> <pre><code>traverse . traverse :: (Traversable g, Traversable f, Applicative a) =&gt; (s -&gt; a t) -&gt; g (f s) -&gt; a (g (f t)) </code></pre> <p>So we've got the key gadget for structure-preserving "do something" operations on lists of lists. The <code>length</code> and <code>splitAt</code> approach works fine for lists (the structure of a list is given by its length), but the essential characteristic of lists which enables that approach is already pretty much bottled by the <code>Traversable</code> class.</p> <p>Now we need to figure out how to "do something". We want to replace the old elements with new things drawn successively from a supply stream. If we were allowed the side-effect of updating the supply, we could say what to do at each element: "return <code>head</code> of supply, updating supply with its <code>tail</code>". The <code>State s</code> monad (in <code>Control.Monad.State</code> which is an instance of <code>Applicative</code>, from <code>Control.Applicative</code>) lets us capture that idea. The type <code>State s a</code> represents computations which deliver a value of type <code>a</code> whilst mutating a state of type <code>s</code>. Typical such computations are made by this gadget.</p> <pre><code>state :: (s -&gt; (a, s)) -&gt; State s a </code></pre> <p>That's to say, given an initial state, just compute the value and the new state. In our case, <code>s</code> is a stream, <code>head</code> gets the value, <code>tail</code> gets the new state. The <code>&amp;&amp;&amp;</code> operator (from <code>Control.Arrow</code>) is a nice way to glue two functions on the same data to get a function making a pair. So</p> <pre><code>head &amp;&amp;&amp; tail :: [x] -&gt; (x, [x]) </code></pre> <p>which makes</p> <pre><code>state $ head &amp;&amp;&amp; tail :: State [x] x </code></pre> <p>and thus</p> <pre><code>const . state $ head &amp;&amp;&amp; tail :: u -&gt; State [x] x </code></pre> <p>explains what to "do" with each element of the old container, namely ignore it and take a new element from the head of the supply stream.</p> <p>Feeding that into <code>(traverse . traverse)</code> gives us a big mutatey traversal of type</p> <pre><code>f (g u) -&gt; State [x] (f (g x)) </code></pre> <p>where <code>f</code> and <code>g</code> are any <code>Traversable</code> structures (e.g. lists).</p> <p>Now, to extract the function we want, taking the initial supply stream, we need to unpack the state-mutating computation as a function from initial state to final value. That's what this does:</p> <pre><code>evalState :: State s a -&gt; s -&gt; a </code></pre> <p>So we end up with something in</p> <pre><code>f (g u) -&gt; [x] -&gt; f (g x) </code></pre> <p>which had better get flipped if it's to match the original spec.</p> <p><strong>tl;dr</strong> The <code>State [x]</code> monad is a readymade tool for describing computations which read and update an input stream. The <code>Traversable</code> class captures a readymade notion of structure-preserving operation on containers. The rest is plumbing (and/or golf).</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload