Closed ekmett closed 11 years ago
I took the code in a rather different direction than, zippo
, or rather in a more extreme notational direction.
A Zipper
in lens
looks like
myZipper :: Top :> Foo :> Bar :> Baz
The only use of the Zipper
name is for the class used to package back up the re-zipped value in the end.
While others sleep, you code :) This is great, and I'm looking forward to studying the final implementation you release. I've always thought a lens-based zipper was a great motivating higher-order use of lenses, and useful for guiding lens lib. design and justifying the claim that they're an abstraction that should be embraced more fully; though I'm skeptical of the need for zippers, beyond a few very specific applications like xmonad.
IYI here are the areas I was planning on focusing on (and might still execute on) in zippo
in the near future:
define a few combinators that form a pleasant mini-eDSL for zipper operations, e.g. (.^>) :: (a -> Zipper st b) -> (b -> Zipper st b -> c) -> a -> c
which allows binding to the focus, then composing additional zipper operations (better name might be \>>
) as in:
zscan a = zipper >>> moveP fstL >>> moveP fstL >>> modf (+a) .^>
\a-> moveUp >>> moveP sndL >>> modf (+a) .^>
\a-> moveUp >>> moveUp >>> moveP sndL >>> moveP fstL >>> modf (+a) .^>
\a-> moveUp >>> moveP sndL >>> modf (+a) >>> close
I can get you the other combinators I've found useful if you're interested.
I'd appreciate it if you'd mention my name, and reference my work on pez
and zippo
in the code or docs somewhere, when you end up releasing; to the best of my knowledge the lens-based zipper approach is novel (if obvious in hindsight); as I think are the level of type-safety, and support for heterogeneous motions provided by zippo
(although it looks like Oleg's Scrap Your Zipper work uses a similar approach) and save/restore/etc junk in 'pez'.
Happy hacking!
I'm currently planning to largely ignore performance issues. I don't anticipate they'll be too bad, given that it gets to ride the same performance benefits that lens
provides elsewhere.
Regarding zipper operations, one of the projects I have in the work is issue #54, which is to port back the Lensed
monad I helped built for snap
a year or two back at Hac φ. I figure If I can port that using a Zipper
rather than the single Lens
like I do there, then the breadcrumb might actually be the website breadcrumb.
This would wind up being similar to your 2.) DSL, except with horizontal (type changing) motions effectively guarded by recursion.
I was planning on doing a haddock pass over the code today. Of course, I'll definitely include your name and a nod to zippo
. My apologies for more or less wholesale stealing the design and running with it, but I really wanted it to be a building block for working with LensedT
(which I suppose is now, probably, ZippedT
)
I've had a lens based zipper in code before, but I must confess, I like the breadcrumb-like signature of your zippo
model better than the version i was using. I was just capturing the types of the start and end as a thrist which meant i couldn't really do a type safe 'up' motion, but only give you an existential context when you moved up, which required you to work CPS'd.
On the other hand, the existential context trick may still prove to be valuable for 'long range' motions like you have in pez.
All great stuff. And no apologies necessary; tis the nature of OSS, and it's nice to see the ideas validated. I just figured I'd let you know what would offend my vanity now rather than after the fact.
On Wed, Sep 19, 2012 at 12:56 PM, Edward A. Kmett notifications@github.comwrote:
I'm currently planning to largely ignore performance issues. I don't anticipate they'll be too bad, given that it gets to ride the same performance benefits that lens provides elsewhere.
Regarding zipper operations, one of the projects I have in the work is issue #54 https://github.com/ekmett/lens/issues/54, which is to port back the Lensed monad I helped built for snap a year or two back at hac phi. I figure If I can port that using a Zipper rather than the single Lens like I do there, then the breadcrumb can actually be the website breadcrumb.
This would wind up being similar to your #2https://github.com/ekmett/lens/issues/2dsl, except with horizontal (type changing) motions effectively guarded by recursion.
I was planning on doing a haddock pass over the code today. Of course, I'll definitely include your name and a nod to zippo. My apologies for more or less wholesale stealing the design and running with it, but I really wanted it to be a building block for working with LensedT (which I suppose is now, probably, ZippedT)
I've had a lens based zipper in code before, but I must confess, I like the breadcrumb-like signature of your zippo model better than the version i was using. I was just capturing the types of the start and end as a thrist which meant i couldn't really do a type safe 'up' motion, but only give you an existential context when you moved up, which required you to work CPS'd.
— Reply to this email directly or view it on GitHubhttps://github.com/ekmett/lens/issues/50#issuecomment-8697922.
Regarding your .^>
combinator, I'm definitely interested in what has worked out well for you in practice.
My first thought was that a variant that fits the stye of the other combinators in lens
a little better might be
(%>) :: (a :> b) -> (b -> (a :> b) -> c) -> c
with a fixity matching %
, and possibly a ^%>
with a fixity matching the tighter fixity of ^%
.
But, er, I guess that doesn't work:
z %> \b -> right1 %> \c -> left1 % focus .~ (b + c)
That doesn't look like it works because the associativity is wrong. and the \
captures the tail.
Perhaps I do need to add a few cps'd combinators at the infixr 1
level to match (>>>
) like the one you proposed.
I've been considering adding a zipper module for some time. I hacked up @jberryman's
zippo
library to uselens
.Issues:
Where to put it?
If it lived in
Control.Lens.Zipper
it would be odd if it wasn't exported fromControl.Lens
, (since I do re-exportControl.Lens.*
for everything exceptControl.Lens.Internal
, but if it was exported fromControl.Lens
it would take a lot of useful names that I've deliberately avoided touching because they are popular in end user code.