<br><br><div class="gmail_quote">On Mon, Jul 26, 2010 at 9:00 PM, Brandon Simmons <span dir="ltr">&lt;<a href="mailto:brandon.m.simmons@gmail.com">brandon.m.simmons@gmail.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
I had the idea for a simple generic Zipper data structure that I<br>
thought would be possible to implement using type-threaded lists<br>
provided by Gabor Greif&#39;s thrist package:<br>
<br>
    <a href="http://hackage.haskell.org/package/thrist" target="_blank">http://hackage.haskell.org/package/thrist</a><br>
<br>
...and the fclabels package by Sebastiaan Visser, Erik Hesselink,<br>
Chris Eidhof and Sjoerd Visscher:<br>
<br>
    <a href="http://hackage.haskell.org/package/fclabels" target="_blank">http://hackage.haskell.org/package/fclabels</a><br>
<br>
It would (ideally) work as follows:<br>
<br>
- the zipper would consist simply of a tuple:<br>
       (type threaded list of constructor sections , current &quot;context&quot;)<br>
- in the type threaded list we store functions (constructor with hole<br>
-&gt; complete constructor), so the<br>
    &quot;one hole context&quot; is represented as a lambda expression where the<br>
free variable will be filled<br>
    by the current &quot;context&quot; (the snd of the tuple)<br>
- we &quot;go down&quot; through our structure by passing to our `moveTo`<br>
function a first-class label<br>
    corresponding to the constructor we want to descend into. `moveTo`<br>
uses this both as a &quot;getter&quot;<br>
    to extract the next level down from the current level, and as a<br>
&quot;setter&quot; to form the lambda expression<br>
    which acts as the &quot;constructor with a piece missing&quot;<br>
- &quot;going up&quot; means popping the head off the thrist and applying it to<br>
the current context, making that<br>
    the new context, exiting the zipper would be a fold in the same manner<br>
<br>
<br>
After throwing together a quick attempt I realized that I&#39;m not sure<br>
if it would be possible to make the `moveUp` function type-check and<br>
be usable. I&#39;m still new to GADTs, existential types, template haskell<br>
etc. and am stuck.<br>
<br>
Here is the code I wrote up, which doesn&#39;t currently compile:<br>
<br>
<br>
----------------------------------  START CODE -------------------------------<br>
<br>
{-# LANGUAGE TypeOperators, GADTs #-}<br>
module ZipperGenerator<br>
    (<br>
      viewC   --lets user pattern match against context<br>
    , moveTo<br>
    , moveUp<br>
    , genZippers<br>
    , zipper<br>
    , unzipper<br>
    , (:-&gt;)<br>
    , ZipperGenerator<br>
    , Zipper<br>
    ) where<br>
<br>
-- these provide the secret sauce<br>
import Data.Record.Label<br>
import Data.Thrist<br>
import <a href="http://Language.Haskell.TH" target="_blank">Language.Haskell.TH</a><br>
<br>
<br>
type ZipperGenerator = [Name] -&gt; Q [Dec]<br>
<br>
-- the Template Haskell function that does the work of generating<br>
-- first-class labels used to move about the zipper:<br>
genZippers :: ZipperGenerator<br>
genZippers = mkLabels<br>
<br>
-- hide the innards:<br>
newtype Zipper t c = Z (Thrist (-&gt;) c t, c)<br>
<br>
-- returns the current &quot;context&quot; (our location in the zipper) for pattern<br>
-- matching and inspection:<br>
viewC :: Zipper t c -&gt; c<br>
viewC (Z(_,c)) = c<br>
<br>
-- takes a first-class label corresponding to the record in the current context<br>
-- that we would like to move to:<br>
moveTo :: (c :-&gt; c&#39;) -&gt; Zipper t c -&gt; Zipper t c&#39;<br>
moveTo lb (Z(thr,c)) = Z (Cons (\a-&gt; set lb a c) thr , get lb c)<br>
<br>
<br>
-- backs up a level in the zipper, returning `Nothing` if we are already at the<br>
-- top level:<br>
moveUp :: Zipper t c -&gt; Maybe (Zipper t b)<br>
moveUp (Z (Nil,_)) = Nothing<br>
moveUp (Z (Cons f thr,c)) = Just $ Z (thr, f c)<br>
<br>
-- create zipper with focus on topmost constructor level:<br>
zipper :: t -&gt; Zipper t t<br>
zipper t = Z (Nil,t)<br>
<br>
-- close zipper<br>
unzipper :: Zipper t c -&gt; t<br>
unzipper (Z(thr,c)) = undefined --foldThrist ($) id thr c<br></blockquote><div><br></div><div>Hmm...I think you just need to change ($) to (.).  I haven&#39;t tested it.  But, if you have Thrist (-&gt;) c t, then what you have is a transformation from c to t, or more simply, c -&gt; t.  So, conceptually at least, you just need to compose the elements in your Thrist.  ($) is application, but in the space of functions it is identity.  So, if you think the elements in your thrist as being values in the space of functions, you&#39;re asking for a right fold that is like, v1 `id` (v2 `id` (v3 `id` ...), which I hope you agree doesn&#39;t make that much sense.  So try this:</div>
<div>unzipper (Z(thr,c)) = foldThrist (.) id thr c</div><div><br></div><div>In the darcs source we use our own custom thrists for storing sequences of patches.  We have two variants, forward lists (FL) and reverse lists (RL).  In our parlance, we have foldlFL defined thusly:</div>
<div>foldlFL :: (forall w y. a -&gt; b w y -&gt; a) -&gt; a -&gt; FL b x z -&gt; a</div><div>foldlFL _ x NilFL = x</div><div>foldlFL f x (y:&gt;:ys) = foldlFL f (f x y) ys</div><div><br></div><div>We don&#39;t use Control.Arrow, so in our notation the &#39;b&#39; in the type signature plays the same role as (~&gt;) but in prefix notation, of course.  And we use (:&gt;:) instead of Cons.  It&#39;s supposed to look like normal list cons but with an arrow pointing forward.  The cons for RL is (:&lt;:).  Perhaps we should use arrow though, as I think that looks pretty nice.</div>
<div><br></div><div>For comparison, here is the definition of foldThrist:</div><div>foldThrist :: (forall i j k . (i ~&gt; j) -&gt; (j ~&gt; k) -&gt; (i ~&gt; k))<br>-&gt; c ~&gt; c<br>-&gt; Thrist (~&gt;) a c<br>-&gt; a ~&gt; c<br>
foldThrist _ v Nil = v<br>foldThrist f v (Cons h t) = h `f` (foldThrist f v t)</div><div><br></div><div>As you can see, our fold is a left fold and the thrist fold is a right fold.  I don&#39;t think a left fold will help you here, but you might keep it in mind as it should be easy to define for thrists, should you need it.</div>
<div><br></div><div>Florent Becker created zippers for the darcs custom FL/RL types recently:</div><div><a href="http://darcs.net/src/Darcs/Witnesses/WZipper.hs">http://darcs.net/src/Darcs/Witnesses/WZipper.hs</a></div><div>
<br></div><div>Don&#39;t let the C(foo) in the types throw you off.  That&#39;s just a CPP macro that conditionally expands to foo or nothing depending on whether the type threading is turned on or off (cabal flag is -ftype-witnesses vs. -f-type-witnesses).  His approach is quite different than yours.  I should probably study the fclabels package.</div>
<div><br></div><div>Thanks for the interesting code!</div><div>Jason</div></div>