Skip to content

Instantly share code, notes, and snippets.

@AndrasKovacs
Last active December 15, 2015 21:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AndrasKovacs/5325678 to your computer and use it in GitHub Desktop.
Save AndrasKovacs/5325678 to your computer and use it in GitHub Desktop.
Generic bidirectional zipper for any Traversable. Based on Oleg Kiselyov's article: http://okmij.org/ftp/continuations/zipper.html#traversable I've no idea currently whether this has decent performance. It goes leftward by reverting to a saved previous continuation, while also saving the edits we've made on nodes to the right.
import qualified Data.Traversable as T
import Control.Monad.Cont
data Zipper t a = ZDone (t a) | Zipper a (Maybe a -> Zipper t a)
data BiZip t a = BiZip [Maybe a] -- edits we've done on the left
[Maybe a] -- edits we've done on the right
[Zipper t a] -- saved Zippers from the left edits
mkZipper :: T.Traversable t => t a -> Zipper t a
mkZipper t = (`runCont` id) $ T.mapM yield t >>= return . ZDone
where yield a = cont $ \k -> Zipper a (k . maybe a id)
mkBiZipper :: T.Traversable t => t a -> BiZip t a
mkBiZipper t = BiZip [] (repeat Nothing) [mkZipper t]
next :: BiZip t a -> Maybe (BiZip t a)
next (BiZip ps (f:fs) zs@(Zipper _ k:_)) = Just $ BiZip (f:ps) fs (k f:zs)
next _ = Nothing
prev :: BiZip t a -> Maybe (BiZip t a)
prev (BiZip (p:ps) fs (z:zs)) = Just $ BiZip ps (p:fs) zs
prev (BiZip [] _ _) = Nothing
update :: a -> BiZip t a -> BiZip t a
update a (BiZip ps (_:fs) zs) = BiZip ps (Just a:fs) zs
value :: BiZip t a -> a
value (BiZip _ (f:_) (Zipper a _:_)) = maybe a id f
modifyVal :: (a -> a) -> BiZip t a -> BiZip t a
modifyVal g (BiZip ps (f:fs) zs@(Zipper a _:_)) = BiZip ps (Just f':fs) zs
where f' = maybe (g a) g f
zipUp :: BiZip t a -> t a
zipUp (BiZip _ fs (z:_)) = go z fs where
go (Zipper _ k) (f:fs) = go (k f) fs
go (ZDone a) _ = a
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment