CC-delcont-0.2: Control/Monad/CC/Cursor.hs
{-# LANGUAGE GADTs, MultiParamTypeClasses, FunctionalDependencies #-}
-------------------------------------------------------------------------------
-- |
-- Module : Control.Monad.CC.Cursor
-- Copyright : (c) Dan Doel
-- License : MIT
--
-- Maintainer : Dan Doel
-- Stability : Experimental
-- Portability : Non-portable (Generalized algebraic data types,
-- Functional Dependencies)
--
-- Implements various cursor datatypes for iterating over collections
module Control.Monad.CC.Cursor (
Cursor(..),
Iterator,
generator,
iterator,
current,
next,
open,
update,
-- Walkable(..),
-- Zipper,
-- zipper,
-- previousDir,
-- currentTerm,
-- move
) where
import Prelude hiding (zip, mapM, mapM_)
import Control.Monad hiding (mapM, mapM_)
import Control.Monad.CC
import Data.Maybe
import Data.Foldable
import Data.Traversable hiding (traverse)
-- | A generalized type that represents a reified data structure traversal.
-- The other traversal data types in this module are special cases of this
-- general type. Cursor is parameterized by four types:
--
-- m : The monad in which the Cursor object is usable.
--
-- r : The result type, which will be stored in the cursor once the traversal
-- has been completed.
--
-- b : The type that the cursor expects to receive before moving on to the
-- next element in the traversal.
--
-- a : The element type to which the Cursor provides access at each step in
-- the traversal.
data Cursor m r b a where
Current :: Monad m => a -> (b -> m (Cursor m r b a)) -> Cursor m r b a
Done :: Monad m => r -> Cursor m r b a
-- | A simple iterator, which provides a way to view each of the elements of
-- a data structure in order.
type Iterator m a = Cursor m () () a
-- | A function for making a cursor out of a free form generator, similar to
-- using 'yield' in Ruby or Python. For example:
--
-- > generator $ \yield -> do a <- yield 1 ; yield 2 ; b <- yield 3 ; return [a,b]
generator :: MonadDelimitedCont p s m => ((a -> m b) -> m r) -> m (Cursor m r b a)
generator f = reset (\p -> Done `liftM` f (yield p))
where yield p a = shift p (\k -> return $ Current a (k . return))
-- A general cursor builder; takes the traversal function, a data structure, and
-- returns a corresponding cursor. Currently not exported, just used internally.
makeCursor :: (MonadDelimitedCont p s m) =>
((a -> m b) -> t -> m r) -> t -> m (Cursor m r b a)
makeCursor iter t = generator $ flip iter t
-- | Creates an Iterator that will yield each of the elements of a Foldable in
-- order.
iterator :: (Foldable t, MonadDelimitedCont p s m) => t a -> m (Iterator m a)
iterator = makeCursor mapM_
-- | Advances an Iterator to the next element (has no effect on a finished Iterator).
next :: Iterator m a -> m (Iterator m a)
next = update ()
-- | Extracts the current element from a cursor, if applicable.
current :: Cursor m r b a -> Maybe a
current (Done _) = Nothing
current (Current a _) = Just a
-- | Begins an updating traversal over a Traversable structure. At each step,
-- the cursor will hold an element of type a, and providing an element of type
-- b will move on to the next step. When done, a new Traversable object holding
-- elements of type b will be available.
open :: (Traversable t, MonadDelimitedCont p s m) => t a -> m (Cursor m (t b) b a)
open = makeCursor mapM
-- | Provides an item to a Cursor, moving on to the next step in the traversal.
-- (has no effect on a finished Cursor).
update :: b -> Cursor m r b a -> m (Cursor m r b a)
update _ c@(Done _) = return c
update b (Current _ k) = k b
-- Removing for now. This isn't remotely done, and I need to reread ccshan's
-- stuff on zippers and such before I can begin to get it right.
{-
class Direction d where
nextD :: d -> d
class Direction d => Walkable t d | t -> d where
walk :: Monad m => (d -> t -> m (Maybe t, d)) -> t -> m t
data ListDir = LLeft | LRight
instance Direction ListDir where
nextD = id
instance Walkable [a] ListDir where
walk tr ll = fromMaybe ll `liftM` traverse LRight ll
where
traverse d l = do (ml, d') <- tr d l
let l' = fromMaybe l ml
maybe ml Just `liftM` select l' d'
select _ LLeft = return Nothing
select l@(x:xs) LRight = do l' <- liftM (x:) `liftM` traverse LRight xs
maybe l' Just `liftM` traverse LLeft (fromMaybe l l')
select [] LRight = maybe Nothing Just `liftM` traverse LLeft []
type Zipper m t d = Cursor m t (Maybe t, d) (d,t)
zipper :: (MonadDelimitedCont p s m, Walkable t d) => t -> m (Zipper m t d)
zipper = makeCursor $ walk . curry
previousDir :: Zipper m t d -> Maybe d
previousDir (Done _) = Nothing
previousDir (Current (d,_) _) = Just d
currentTerm :: Zipper m t d -> t
currentTerm (Done t) = t
currentTerm (Current (_,t) _) = t
move :: d -> Zipper m t d -> m (Zipper m t d)
move _ z@(Done _) = return z
move d (Current _ k) = k (Nothing, d)
-}