<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body text="#000000" bgcolor="#FFFFFF">
    Hi,<br>
    <br>
    <blockquote type="cite" cite="mid:20180227105232.GH27273@weber">
      <pre wrap="">There's a myth floating around that "Arrow is much less useful because it
forces you to implement arr".  In fact, Arrow without arr would be as
useless as Applicative without fmap.  In almost all situations where you are
stymied by arr a small redesign will solve the whole problem.  In fact, you
need to get into the realm of linear-types-like things before arr is too
much (and even then a *linear* arr would be fine).

I designed a library for constructing Postgres queries and it uses an Arrow
interface.

    <a class="moz-txt-link-freetext" href="https://hackage.haskell.org/package/opaleye-0.5.3.0/docs/Opaleye-Internal-QueryArr.html">https://hackage.haskell.org/package/opaleye-0.5.3.0/docs/Opaleye-Internal-QueryArr.html</a>

Naturally there is no way to run an arbitrary Haskell function "in the
database".  This is not an impediment because everything that the database
acts on inside the arrow type (QueryArr) is wrapped in an abstract type
(Column).  This means the only way that arbitrary Haskell functions can be
used inside the arrow is as a sort of "partial compilation".  There is, in
effect, a staging restriction.  Haskell functions a -> b run at "query
compile time" and Postgres functions run at "query run time".
</pre>
    </blockquote>
    <br>
    <p>
      Hm. Interesting point. And a nice coincidence that you call
      Applicative
      without fmap "useless". I just recently saw one of those. It
      *did* feel like there might be a better structure, but I couldn't
      pin it
      down. Maybe your technique works in that context as well? Would
      you mind
      having a look? I'd like to have my eyes opened in that direction.<br>
    </p>
    <p>
    </p>
    <p>The structure in question are XML-Picklers, i.e. tools to convert
      to and from XML. The original types are from <a
        moz-do-not-send="true"
href="https://hackage.haskell.org/package/hxt-9.3.1.16/docs/src/Text-XML-HXT-Arrow-Pickle-Xml.html">HXT</a>,
      but for the purpose of discussion we can simplify them to</p>
    <pre><span class="hs-keyword">    data</span> <span class="hs-conid">PU</span> <span class="hs-varid">a</span> <span class="hs-keyglyph">=</span> <span class="hs-conid">PU</span> <span class="hs-layout">{</span> <span class="hs-varid">appPickle</span>   <span class="hs-keyglyph">::</span> <span class="hs-varid">a</span> <span class="hs-keyglyph">-></span> <span class="hs-conid">XmlState</span> <span class="hs-keyglyph">-></span> <span class="hs-conid">XmlState</span>                    -- turn a value into XML
                   <span class="hs-layout">,</span> <span class="hs-varid">appUnPickle</span> <span class="hs-keyglyph">::</span> <span class="hs-conid">XmlState</span> <span class="hs-keyglyph">-></span> <span class="hs-layout">(Either </span><span class="hs-conid">UnpickleErr</span> <span class="hs-varid">a</span><span class="hs-layout">,</span> <span class="hs-conid">XmlState</span><span class="hs-layout">) -- turn XML into a value</span><span class="hs-varid"></span>
                   <span class="hs-layout">}
    
</span><span class="hs-layout">    -- "pure"
    </span><span class="hs-definition">xpLift</span> <span class="hs-keyglyph">::</span> <span class="hs-varid">a</span> <span class="hs-keyglyph">-></span> <span class="hs-conid">PU</span> <span class="hs-varid">a
   </span> <span class="hs-definition">xpLift</span> <span class="hs-varid">x</span> <span class="hs-keyglyph">=</span>  <span class="hs-conid">PU</span> <span class="hs-layout">{</span> <span class="hs-varid">appPickle</span>   <span class="hs-keyglyph">=</span> <span class="hs-varid">const</span> <span class="hs-varid">id</span>
                   <span class="hs-layout">,</span> <span class="hs-varid">appUnPickle</span> <span class="hs-keyglyph">=</span> pure <span class="hs-varid">x</span>
                   <span class="hs-layout">}</span><span class="hs-layout">    
</span><span class="hs-layout">   
</span><span class="hs-comment">    -- Combine two picklers sequentially</span>
<span class="hs-comment"><span class="hs-comment">    </span>-- If the first fails during</span> <span class="hs-comment">unpickling, the whole unpickler fails</span><span class="hs-definition">
</span><span class="hs-definition"><span class="hs-comment">    </span>xpSeq</span> <span class="hs-keyglyph">::</span> <span class="hs-layout">(</span><span class="hs-varid">b</span> <span class="hs-keyglyph">-></span> <span class="hs-varid">a</span><span class="hs-layout">)</span> <span class="hs-keyglyph">-></span> <span class="hs-conid">PU</span> <span class="hs-varid">a</span> <span class="hs-keyglyph">-></span> <span class="hs-layout">(</span><span class="hs-varid">a</span> <span class="hs-keyglyph">-></span> <span class="hs-conid">PU</span> <span class="hs-varid">b</span><span class="hs-layout">)</span> <span class="hs-keyglyph">-></span> <span class="hs-conid">PU</span> <span class="hs-varid">b</span>
<span class="hs-definition"><span class="hs-comment">    x</span>pSeq</span> <span class="hs-varid">f</span> <span class="hs-varid">pa</span> <span class="hs-varid">k</span>
<span class="hs-comment">    </span>   <span class="hs-keyglyph">=</span> <span class="hs-conid">PU</span> <span class="hs-layout">{</span> <span class="hs-varid">appPickle</span>   <span class="hs-keyglyph">=</span> <span class="hs-layout">(</span> <span class="hs-keyglyph">\</span> <span class="hs-varid">b</span> <span class="hs-keyglyph">-></span> <span class="hs-keyword">let</span> <span class="hs-varid">a</span> <span class="hs-keyglyph">=</span> <span class="hs-varid">f</span> <span class="hs-varid">b</span> <span class="hs-keyword">in</span> <span class="hs-varid">appPickle</span> <span class="hs-varid">pa</span> <span class="hs-varid">a</span> <span class="hs-varop">.</span> <span class="hs-varid">appPickle</span> <span class="hs-layout">(</span><span class="hs-varid">k</span> <span class="hs-varid">a</span><span class="hs-layout">)</span> <span class="hs-varid">b</span> )
<span class="hs-comment">    </span>        <span class="hs-layout">,</span> <span class="hs-varid">appUnPickle</span> <span class="hs-keyglyph">=</span> <span class="hs-varid">appUnPickle</span> <span class="hs-varid">pa</span> <span class="hs-varop">>>=</span> <span class="hs-layout">(</span><span class="hs-varid">appUnPickle</span> <span class="hs-varop">.</span> <span class="hs-varid">k</span><span class="hs-layout">)</span><span class="hs-comment">    </span>
<span class="hs-comment">    </span>        <span class="hs-layout">}</span><span class="hs-layout">

</span><span class="hs-comment">    -- Pickle a pair of values sequentially</span><span class="hs-comment"></span>
    <span class="hs-definition">xpPair</span> <span class="hs-keyglyph">::</span> <span class="hs-conid">PU</span> <span class="hs-varid">a</span> <span class="hs-keyglyph">-></span> <span class="hs-conid">PU</span> <span class="hs-varid">b</span> <span class="hs-keyglyph">-></span> <span class="hs-conid">PU</span> <span class="hs-layout">(</span><span class="hs-varid">a</span><span class="hs-layout">,</span> <span class="hs-varid">b</span><span class="hs-layout">)</span>
<span class="hs-definition">    xpPair</span> <span class="hs-varid">pa</span> <span class="hs-varid">pb</span> <span class="hs-keyglyph">=</span> <span class="hs-layout">(</span> <span class="hs-varid">xpSeq</span> <span class="hs-varid">fst</span> <span class="hs-varid">pa</span> <span class="hs-layout">(</span><span class="hs-keyglyph">\</span> <span class="hs-varid">a</span> <span class="hs-keyglyph">-></span> <span class="hs-varid">xpSeq</span> <span class="hs-varid">snd</span> <span class="hs-varid">pb</span> <span class="hs-layout">(</span><span class="hs-keyglyph">\</span> <span class="hs-varid">b</span> <span class="hs-keyglyph">-></span><span class="hs-varid"> xpLift</span> <span class="hs-layout">(</span><span class="hs-varid">a</span><span class="hs-layout">,</span><span class="hs-varid">b</span><span class="hs-layout">)</span><span class="hs-layout">)</span><span class="hs-layout">)</span> <span class="hs-layout">)

</span><span class="hs-definition">    -- The closest equivalent to "fmap"
    xpWrap </span><span class="hs-keyglyph">::</span> <span class="hs-layout">(</span><span class="hs-varid">a</span> <span class="hs-keyglyph">-></span> <span class="hs-varid">b</span><span class="hs-layout">,</span> <span class="hs-varid">b</span> <span class="hs-keyglyph">-></span> <span class="hs-varid">a</span><span class="hs-layout">)</span> <span class="hs-keyglyph">-></span> <span class="hs-conid">PU</span> <span class="hs-varid">a</span> <span class="hs-keyglyph">-></span> <span class="hs-conid">PU</span> <span class="hs-varid">b</span> 
<span class="hs-layout"></span><span class="hs-layout"></span></pre>
    <p>Now: This is not exactly an Applicative. If it where a functor,
      it would be a (lax) monoidal functor. Taking syntax from the <a
        moz-do-not-send="true"
        href="https://wiki.haskell.org/Typeclassopedia#Alternative_formulation">Typeclassopedia</a>,
      <tt>xpPair</tt> would be <tt>Monoidal</tt>'s <tt>(**)</tt>. And
      a (lax) monoidal functor is exactly an Applicative. If I'm not
      mistaken this structure satisfies all the laws of <tt>Monoidal</tt>
      – except that it is not a functor.</p>
    <p>Obviously there's no way to implement <tt>fmap</tt> because you
      always need to provide functions for both directions, as seen in <tt>xpWrap</tt>.
      So how would you change this structure to make it possible?</p>
    <p>It feels like the underlying problem is the same as with <tt>arr</tt>:
      At first there seems to be no way to lift functions into the
      structure. And we don't want to create two separate types because
      the whole idea of <tt>PU</tt> is to make pairs of related
      picklers and unpicklers composable.<br>
    </p>
    Do I have a blind eye, nourished by that myth that often lifting is
    not possible? Or did I stumble upon that one usecase where there IS
    a useful Applicative-without-fmap?<br>
    <br>
    MarLinn<br>
    <br>
  </body>
</html>