[Haskell-cafe] Partial instance of a class

MarLinn monkleyon at gmail.com
Tue Feb 27 13:28:31 UTC 2018


> 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.
>      https://hackage.haskell.org/package/opaleye-
> 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".

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.

The structure in question are XML-Picklers, i.e. tools to convert to and 
from XML. The original types are from HXT 
but for the purpose of discussion we can simplify them to

data  PU  a  =  PU  {  appPickle    ::  a  ->  XmlState  ->  XmlState                     -- turn a value into XML
                    ,  appUnPickle  ::  XmlState  ->  (Either UnpickleErr  a,  XmlState) -- turn XML into a value
                    } -- "pure" xpLift  ::  a  ->  PU  a   xpLift  x  =   PU  {  appPickle    =  const  id
                    ,  appUnPickle  =  purex
                    }-- Combine two picklers sequentially
-- If the first fails during  unpickling, the whole unpickler failsxpSeq  ::  (b  ->  a)  ->  PU  a  ->  (a  ->  PU  b)  ->  PU  b
xpSeq  f  pa  k
    =  PU  {  appPickle    =  (  \  b  ->  let  a  =  f  b  in  appPickle  pa  a  .  appPickle  (k  a)  b  )
         ,  appUnPickle  =  appUnPickle  pa   >>=  (appUnPickle  .  k)
         }-- Pickle a pair of values sequentially
     xpPair  ::  PU  a  ->  PU  b  ->  PU  (a,  b)
xpPair  pa  pb  =  (  xpSeq  fst  pa  (\  a  ->  xpSeq  snd  pb  (\  b  ->xpLift  (a,b)))  ) -- The closest equivalent to "fmap" xpWrap ::  (a  ->  b,  b  ->  a)  ->  PU  a  ->  PU  b  

Now: This is not exactly an Applicative. If it where a functor, it would 
be a (lax) monoidal functor. Taking syntax from the Typeclassopedia 
xpPair would be Monoidal's (**). And a (lax) monoidal functor is exactly 
an Applicative. If I'm not mistaken this structure satisfies all the 
laws of Monoidal – except that it is not a functor.

Obviously there's no way to implement fmap because you always need to 
provide functions for both directions, as seen in xpWrap. So how would 
you change this structure to make it possible?

It feels like the underlying problem is the same as with arr: 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 PU is 
to make pairs of related picklers and unpicklers composable.

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 


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/haskell-cafe/attachments/20180227/c0a73385/attachment.html>

More information about the Haskell-Cafe mailing list