module Data.List.PointedList where
import Prelude hiding (foldl, foldr, elem)
import Control.Applicative
import Control.Monad
import Data.Binary
import Data.Foldable hiding (find)
import Data.List hiding (length, foldl, foldr, find, elem)
import qualified Data.List as List
import Data.Traversable
data PointedList a = PointedList
{ _reversedPrefix :: [a]
, _focus :: a
, _suffix :: [a]
} deriving (Eq)
instance Binary a => Binary (PointedList a) where
put (PointedList x1 x2 x3) = do put x1; put x2; put x3
get = do liftM3 PointedList get get get
reversedPrefix :: Functor f => ([a] -> f [a]) -> PointedList a -> f (PointedList a)
reversedPrefix f (PointedList ls x rs) = (\ls' -> PointedList ls' x rs) <$> f ls
focus :: Functor f => (a -> f a) -> PointedList a -> f (PointedList a)
focus f (PointedList ls x rs) = (\x' -> PointedList ls x' rs) <$> f x
suffix :: Functor f => ([a] -> f [a]) -> PointedList a -> f (PointedList a)
suffix f (PointedList ls x rs) = (\rs' -> PointedList ls x rs') <$> f rs
prefix :: Functor f => ([a] -> f [a]) -> PointedList a -> f (PointedList a)
prefix f (PointedList ls x rs) = (\ls' -> PointedList (reverse ls') x rs) <$> f (reverse ls)
instance (Show a) => Show (PointedList a) where
show (PointedList ls x rs) = show (reverse ls) ++ " " ++ show x ++ " " ++ show rs
instance Functor PointedList where
fmap f (PointedList ls x rs) = PointedList (map f ls) (f x) (map f rs)
instance Foldable PointedList where
foldr f z (PointedList ls x rs) = foldl (flip f) (foldr f z (x:rs)) ls
instance Traversable PointedList where
traverse f (PointedList ls x rs) = PointedList <$>
(reverse <$> traverse f (reverse ls)) <*> f x <*> traverse f rs
singleton :: a -> PointedList a
singleton x = PointedList [] x []
fromList :: [a] -> Maybe (PointedList a)
fromList [] = Nothing
fromList (x:xs) = Just $ PointedList [] x xs
fromListEnd :: [a] -> Maybe (PointedList a)
fromListEnd [] = Nothing
fromListEnd xs = Just $ PointedList xs' x []
where (x:xs') = reverse xs
replace :: a -> PointedList a -> PointedList a
replace x (PointedList ls _ rs) = PointedList ls x rs
next :: PointedList a -> Maybe (PointedList a)
next (PointedList _ _ []) = Nothing
next p = (Just . tryNext) p
tryNext :: PointedList a -> PointedList a
tryNext p@(PointedList _ _ [] ) = error "cannot move to next element"
tryNext (PointedList ls x (r:rs)) = PointedList (x:ls) r rs
previous :: PointedList a -> Maybe (PointedList a)
previous (PointedList [] _ _ ) = Nothing
previous p = (Just . tryPrevious) p
tryPrevious :: PointedList a -> PointedList a
tryPrevious p@(PointedList [] _ _ ) =
error "cannot move to previous element"
tryPrevious (PointedList (l:ls) x rs) = PointedList ls l (x:rs)
insert :: a -> PointedList a -> PointedList a
insert = insertRight
insertLeft :: a -> PointedList a -> PointedList a
insertLeft y (PointedList ls x rs) = PointedList ls y (x:rs)
insertRight :: a -> PointedList a -> PointedList a
insertRight y (PointedList ls x rs) = PointedList (x:ls) y rs
delete :: PointedList a -> Maybe (PointedList a)
delete = deleteRight
deleteLeft :: PointedList a -> Maybe (PointedList a)
deleteLeft (PointedList [] _ [] ) = Nothing
deleteLeft (PointedList (l:ls) _ rs) = Just $ PointedList ls l rs
deleteLeft (PointedList [] _ (r:rs)) = Just $ PointedList [] r rs
deleteRight :: PointedList a -> Maybe (PointedList a)
deleteRight (PointedList [] _ [] ) = Nothing
deleteRight (PointedList ls _ (r:rs)) = Just $ PointedList ls r rs
deleteRight (PointedList (l:ls) _ []) = Just $ PointedList ls l []
deleteOthers :: PointedList a -> PointedList a
deleteOthers (PointedList _ b _) = PointedList [] b []
length :: PointedList a -> Int
length = foldr (const (+1)) 0
atStart :: PointedList a -> Bool
atStart (PointedList [] _ _) = True
atStart _ = False
atEnd :: PointedList a -> Bool
atEnd (PointedList _ _ []) = True
atEnd _ = False
positions :: PointedList a -> PointedList (PointedList a)
positions p@(PointedList ls x rs) = PointedList left p right
where left = unfoldr (\p -> fmap (join (,)) $ previous p) p
right = unfoldr (\p -> fmap (join (,)) $ next p) p
contextMap :: (PointedList a -> b) -> PointedList a -> PointedList b
contextMap f z = fmap f $ positions z
withFocus :: PointedList a -> PointedList (a, Bool)
withFocus (PointedList a b c) =
PointedList (zip a (repeat False)) (b, True) (zip c (repeat False))
moveTo :: Int -> PointedList a -> Maybe (PointedList a)
moveTo n pl = moveN (n (index pl)) pl
moveN :: Int -> PointedList a -> Maybe (PointedList a)
moveN n pl@(PointedList left x right) = go n left x right
where
go n left x right = case compare n 0 of
GT -> case right of
[] -> Nothing
(r:rs) -> go (n1) (x:left) r rs
LT -> case left of
[] -> Nothing
(l:ls) -> go (n+1) ls l (x:right)
EQ -> Just $ PointedList left x right
find :: Eq a => a -> PointedList a -> Maybe (PointedList a)
find x pl = find' ((x ==) . _focus) $ positions pl
where find' pred (PointedList a b c) =
if pred b then Just b
else List.find pred (merge a c)
merge [] ys = ys
merge (x:xs) ys = x : merge ys xs
index :: PointedList a -> Int
index (PointedList a _ _) = Prelude.length a