<html>
  <head>
    <meta content="text/html; charset=ISO-8859-1"
      http-equiv="Content-Type">
  </head>
  <body bgcolor="#FFFFFF" text="#000000">
    <div class="moz-cite-prefix">On 11/20/12 6:21 PM, Steve Severance
      wrote:<br>
    </div>
    <blockquote
cite="mid:CAGhAMHFUS4ej-GciKvhUWH1zsfr=t8xcohHR6v9xAsr14V6aEA@mail.gmail.com"
      type="cite">
      <div
style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:13px;background-color:rgb(255,255,255)">class
        (ReflectDescriptor a, Typeable a, Wire a) =&gt; ProtoBuf a&nbsp;</div>
      <div
style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:13px;background-color:rgb(255,255,255)"><br>
      </div>
      <div
style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:13px;background-color:rgb(255,255,255)">
        <div>data Expression a b where</div>
        <div>&nbsp; OpenTable :: (ProtoBuf b) =&gt; Int -&gt; Table -&gt;
          Expression () b</div>
        <div>&nbsp; OpenFile :: (ProtoBuf b) =&gt; Int -&gt; String -&gt;
          Expression () b</div>
      </div>
      <div
style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:13px;background-color:rgb(255,255,255)">
        <div>&nbsp; WriteFile :: (Typeable a, ProtoBuf b) =&gt; Int -&gt;
          String -&gt; Expression a b -&gt; Expression b ()</div>
        <div>&nbsp; WriteTable :: (Typeable a, ProtoBuf b) =&gt; Int -&gt;
          Table -&gt; Expression a b -&gt; Expression b ()</div>
      </div>
      <div
style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:13px;background-color:rgb(255,255,255)">&nbsp;
        Map :: (ProtoBuf a, ProtoBuf b, ProtoBuf c) =&gt; Int -&gt; (a
        -&gt; b) -&gt; Expression c a -&gt; Expression a b</div>
      <div
style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:13px;background-color:rgb(255,255,255)">&nbsp;
        LocalMerge :: (ProtoBuf a) =&gt; Int -&gt; [Expression c a]
        -&gt; Expression c a</div>
    </blockquote>
    We can implement a version of the compos operator like so:<br>
    <br>
    compos :: forall m c d. (forall a. a -&gt; m a) -&gt; (forall a b. m
    (a -&gt; b) -&gt; m a -&gt; m b)<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -&gt; (forall e f. Expression e f -&gt; m (Expression e
    f)) -&gt; Expression c d -&gt; m (Expression c d)<br>
    compos ret app f v = <br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case v of<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OpenTable i t -&gt; ret (OpenTable i t)<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OpenFile i s&nbsp; -&gt; ret (OpenFile i s)<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Map i g e -&gt; ret (Map i g) `app` f e<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WriteFile i s e -&gt; ret (WriteFile i s) `app` f e<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WriteTable i t e -&gt; ret (WriteTable i t) `app` f e<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LocalMerge i es -&gt; ret (LocalMerge i) `app` mapm f es<br>
    &nbsp;&nbsp;&nbsp; where <br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mapm :: forall g h. (Expression g h&nbsp; -&gt; m (Expression g
    h)) -&gt; [Expression g h] -&gt; m [Expression g h]<br>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mapm g = foldr (app . app (ret (:)) . g) (ret [])<br>
    <br>
    Then, with this in hand, we get all the usual compos variants:<br>
    <br>
    composOp ::&nbsp; (forall a b. Expression a b -&gt; Expression a b) -&gt;
    Expression c d -&gt; Expression c d<br>
    composOp f = runIdentity . composOpM (Identity . f)<br>
    <br>
    composOpM :: (Monad m) =&gt; (forall a b. Expression a b -&gt; m
    (Expression a b)) -&gt; Expression c d -&gt; m (Expression c d)<br>
    composOpM = compos return ap<br>
    <br>
    composOpM_ :: (Monad m) =&gt; (forall a b. Expression a b -&gt; m
    ()) -&gt; Expression c d -&gt; m ()<br>
    composOpM_ = composOpFold (return ()) (&gt;&gt;)<br>
    <br>
    composOpFold :: b -&gt; (b -&gt; b -&gt; b) -&gt; (forall c d.
    Expression c d -&gt; b) -&gt; Expression e f -&gt; b<br>
    composOpFold z c f = unC . compos (\_ -&gt; C z) (\(C x) (C y) -&gt;
    C (c x y)) (C . f)<br>
    newtype C b a = C { unC :: b }<br>
    <br>
    See Bringert and Ranta's "A Pattern for Almost Compositional
    Functions" for more details:
    <a class="moz-txt-link-freetext" href="http://publications.lib.chalmers.se/records/fulltext/local_75172.pdf">http://publications.lib.chalmers.se/records/fulltext/local_75172.pdf</a><br>
    <br>
    In my experience, compos requires a little work, but it can handle
    just about any data type or family of data types you throw at it.<br>
    <br>
    (note the twist on compos is just an extra rank 2 type to quantify
    over the "a" and "b" in "Expression a b". The same rank 2 type lets
    you write the recursive code almost directly as well [using
    polymorphic recursion] -- compos is just a nice generic way to avoid
    writing the boilerplate traversal repeatedly).<br>
    <br>
    Cheers,<br>
    Gershom<br>
    <br>
  </body>
</html>