Oleg wrote about converting an arbitrary traversable into a zipper.
His code uses delimited continuations, and I puzzled a while (years...) before starting to understand what was going on.
I just read Yield: mainstream delimited continuations.
It looked to me like I could easily change Oleg's zipper can be expressed using "yield" which gives a different view, that I think I might have understood more easily - because I know yield from other languages, and don't properly have my head around continuations (which is basically the point of the "Yield" paper, I think)
So then, my altered version of the zipper on Oleg's page, using yield
:
> import Data.Traversable as T > type Zipper t a = Iterator (Maybe a) a (t a) > make_zipper :: T.Traversable t => t a -> Zipper t a > make_zipper t = run $ T.mapM f t > where > f a = do > r <- yield a > return $ maybe a id r
This is run and yield pretty much as defined on page 10 of the yield paper:
> data Iterator i o r = Result r | Susp o (i -> Iterator i o r) > yield x = shift (\k -> return $ Susp x k) > run x = reset $ x >>= return . Result
and some test code:
> sample = [1,2,3] > main = do > let (Susp a1 k1) = make_zipper sample > print a1 > let (Susp a2 k2) = k1 Nothing > print a2 > let (Susp a3 k3) = k2 $ Just 100 > print a3 > let (Result end) = k3 Nothing > print end
and below, to make this posting properly executable, here's Oleg's library code for shift/reset:
> -- The Cont monad for delimited continuations, implemented here to avoid > -- importing conflicting monad transformer libraries > newtype Cont r a = Cont{runCont :: (a -> r) -> r} > instance Monad (Cont r) where > return x = Cont $ \k -> k x > m >>= f = Cont $ \k -> runCont m (\v -> runCont (f v) k) > reset :: Cont r r -> r > reset m = runCont m id > shift :: ((a -> r) -> Cont r r) -> Cont r a > shift e = Cont (\k -> reset (e k))
Update 1: Changed types from Oleg's Z | ZDone to the yield paper's Susp | Result
No comments:
Post a Comment