{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingStrategies #-}

module Data.List.NonEmpty.Zipper
  ( Zipper

    -- * Accessors
  , lefts
  , rights
  , current

    -- * Traversal
  , left
  , right
  , leftN
  , rightN
  , findLeft
  , findRight
  , start
  , end

    -- * Construction
  , fromNonEmpty
  , fromNonEmptyEnd

    -- ** Update
  , replace
  , delete
  , push
  , pop
  , shift
  , unshift
  , reverse

    -- * Predicates
  , isStart
  , isEnd
  )
where

import Prelude hiding (reverse)
import qualified Prelude

import Control.Comonad
import Control.DeepSeq (NFData)
import Control.Monad (foldM)
import qualified Data.List.NonEmpty as NE
import Data.Maybe (fromMaybe)
import GHC.Generics (Generic)
import Safe (headMay, tailMay)

data Zipper a = Zipper [a] a [a]
  deriving stock (Zipper a -> Zipper a -> Bool
(Zipper a -> Zipper a -> Bool)
-> (Zipper a -> Zipper a -> Bool) -> Eq (Zipper a)
forall a. Eq a => Zipper a -> Zipper a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall a. Eq a => Zipper a -> Zipper a -> Bool
== :: Zipper a -> Zipper a -> Bool
$c/= :: forall a. Eq a => Zipper a -> Zipper a -> Bool
/= :: Zipper a -> Zipper a -> Bool
Eq, Int -> Zipper a -> ShowS
[Zipper a] -> ShowS
Zipper a -> String
(Int -> Zipper a -> ShowS)
-> (Zipper a -> String) -> ([Zipper a] -> ShowS) -> Show (Zipper a)
forall a. Show a => Int -> Zipper a -> ShowS
forall a. Show a => [Zipper a] -> ShowS
forall a. Show a => Zipper a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: forall a. Show a => Int -> Zipper a -> ShowS
showsPrec :: Int -> Zipper a -> ShowS
$cshow :: forall a. Show a => Zipper a -> String
show :: Zipper a -> String
$cshowList :: forall a. Show a => [Zipper a] -> ShowS
showList :: [Zipper a] -> ShowS
Show, (forall a b. (a -> b) -> Zipper a -> Zipper b)
-> (forall a b. a -> Zipper b -> Zipper a) -> Functor Zipper
forall a b. a -> Zipper b -> Zipper a
forall a b. (a -> b) -> Zipper a -> Zipper b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
$cfmap :: forall a b. (a -> b) -> Zipper a -> Zipper b
fmap :: forall a b. (a -> b) -> Zipper a -> Zipper b
$c<$ :: forall a b. a -> Zipper b -> Zipper a
<$ :: forall a b. a -> Zipper b -> Zipper a
Functor, (forall x. Zipper a -> Rep (Zipper a) x)
-> (forall x. Rep (Zipper a) x -> Zipper a) -> Generic (Zipper a)
forall x. Rep (Zipper a) x -> Zipper a
forall x. Zipper a -> Rep (Zipper a) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall a x. Rep (Zipper a) x -> Zipper a
forall a x. Zipper a -> Rep (Zipper a) x
$cfrom :: forall a x. Zipper a -> Rep (Zipper a) x
from :: forall x. Zipper a -> Rep (Zipper a) x
$cto :: forall a x. Rep (Zipper a) x -> Zipper a
to :: forall x. Rep (Zipper a) x -> Zipper a
Generic)
  deriving anyclass (Zipper a -> ()
(Zipper a -> ()) -> NFData (Zipper a)
forall a. NFData a => Zipper a -> ()
forall a. (a -> ()) -> NFData a
$crnf :: forall a. NFData a => Zipper a -> ()
rnf :: Zipper a -> ()
NFData)

instance Foldable Zipper where
  foldMap :: forall m a. Monoid m => (a -> m) -> Zipper a -> m
foldMap a -> m
f (Zipper [a]
ls a
x [a]
rs) = (a -> m) -> [a] -> m
forall m a. Monoid m => (a -> m) -> [a] -> m
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap a -> m
f ([a] -> [a]
forall a. [a] -> [a]
Prelude.reverse [a]
ls) m -> m -> m
forall a. Monoid a => a -> a -> a
`mappend` a -> m
f a
x m -> m -> m
forall a. Monoid a => a -> a -> a
`mappend` (a -> m) -> [a] -> m
forall m a. Monoid m => (a -> m) -> [a] -> m
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap a -> m
f [a]
rs

instance Traversable Zipper where
  traverse :: forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> Zipper a -> f (Zipper b)
traverse a -> f b
f (Zipper [a]
ls a
x [a]
rs) =
    [b] -> b -> [b] -> Zipper b
forall a. [a] -> a -> [a] -> Zipper a
Zipper
      ([b] -> b -> [b] -> Zipper b) -> f [b] -> f (b -> [b] -> Zipper b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ([b] -> [b]
forall a. [a] -> [a]
Prelude.reverse ([b] -> [b]) -> f [b] -> f [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (a -> f b) -> [a] -> f [b]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> [a] -> f [b]
traverse a -> f b
f ([a] -> [a]
forall a. [a] -> [a]
Prelude.reverse [a]
ls))
      f (b -> [b] -> Zipper b) -> f b -> f ([b] -> Zipper b)
forall a b. f (a -> b) -> f a -> f b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> a -> f b
f a
x
      f ([b] -> Zipper b) -> f [b] -> f (Zipper b)
forall a b. f (a -> b) -> f a -> f b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (a -> f b) -> [a] -> f [b]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> [a] -> f [b]
traverse a -> f b
f [a]
rs

-- | The list zipper is a basic comonad
--
-- This instance allows us to create a zipper of all possible states of
-- traversing the zipper with 'left' and 'right'.
--
-- >>> duplicate $ fromNonEmpty $ NE.fromList [1, 2, 3]
-- Zipper [] (Zipper [] 1 [2,3]) [Zipper [1] 2 [3],Zipper [2,1] 3 []]
instance Comonad Zipper where
  extract :: forall a. Zipper a -> a
extract = Zipper a -> a
forall a. Zipper a -> a
current
  duplicate :: forall a. Zipper a -> Zipper (Zipper a)
duplicate Zipper a
z =
    let dupWith :: (t -> Maybe t) -> t -> [t]
dupWith t -> Maybe t
f t
r =
          case t -> Maybe t
f t
r of
            Maybe t
Nothing -> [t
r]
            Just t
x -> t
r t -> [t] -> [t]
forall a. a -> [a] -> [a]
: (t -> Maybe t) -> t -> [t]
dupWith t -> Maybe t
f t
x
    in  [Zipper a] -> Zipper a -> [Zipper a] -> Zipper (Zipper a)
forall a. [a] -> a -> [a] -> Zipper a
Zipper
          ([Zipper a]
-> (Zipper a -> [Zipper a]) -> Maybe (Zipper a) -> [Zipper a]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [] ((Zipper a -> Maybe (Zipper a)) -> Zipper a -> [Zipper a]
forall {t}. (t -> Maybe t) -> t -> [t]
dupWith Zipper a -> Maybe (Zipper a)
forall a. Zipper a -> Maybe (Zipper a)
left) (Maybe (Zipper a) -> [Zipper a]) -> Maybe (Zipper a) -> [Zipper a]
forall a b. (a -> b) -> a -> b
$ Zipper a -> Maybe (Zipper a)
forall a. Zipper a -> Maybe (Zipper a)
left Zipper a
z)
          Zipper a
z
          ([Zipper a]
-> (Zipper a -> [Zipper a]) -> Maybe (Zipper a) -> [Zipper a]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [] ((Zipper a -> Maybe (Zipper a)) -> Zipper a -> [Zipper a]
forall {t}. (t -> Maybe t) -> t -> [t]
dupWith Zipper a -> Maybe (Zipper a)
forall a. Zipper a -> Maybe (Zipper a)
right) (Maybe (Zipper a) -> [Zipper a]) -> Maybe (Zipper a) -> [Zipper a]
forall a b. (a -> b) -> a -> b
$ Zipper a -> Maybe (Zipper a)
forall a. Zipper a -> Maybe (Zipper a)
right Zipper a
z)

-- | Get the current focus of the @'Zipper'@ cursor
--
-- This is a synonym for 'Control.Comonad.extract'
--
-- >>> current . fromNonEmpty $ NE.fromList [1, 2, 3]
-- 1
current :: Zipper a -> a
current :: forall a. Zipper a -> a
current (Zipper [a]
_ a
curr [a]
_) = a
curr

-- | Get all values on the left of the cursor
--
-- >>> lefts . fromNonEmptyEnd $ NE.fromList [1, 2, 3]
-- [1,2]
lefts :: Zipper a -> [a]
lefts :: forall a. Zipper a -> [a]
lefts (Zipper [a]
ls a
_ [a]
_) = [a] -> [a]
forall a. [a] -> [a]
Prelude.reverse [a]
ls

-- | Get all values on the right of the cursor
--
-- >>> rights . fromNonEmpty $ NE.fromList [1, 2, 3]
-- [2,3]
rights :: Zipper a -> [a]
rights :: forall a. Zipper a -> [a]
rights (Zipper [a]
_ a
_ [a]
rs) = [a]
rs

-- | Move the current focus of the cursor to the left
--
-- >>> left . fromNonEmptyEnd $ NE.fromList [1, 2, 3]
-- Just (Zipper [1] 2 [3])
left :: Zipper a -> Maybe (Zipper a)
left :: forall a. Zipper a -> Maybe (Zipper a)
left (Zipper [a]
ps a
curr [a]
ns) = do
  a
newCurr <- [a] -> Maybe a
forall a. [a] -> Maybe a
headMay [a]
ps
  Zipper a -> Maybe (Zipper a)
forall a. a -> Maybe a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Zipper a -> Maybe (Zipper a)) -> Zipper a -> Maybe (Zipper a)
forall a b. (a -> b) -> a -> b
$ [a] -> a -> [a] -> Zipper a
forall a. [a] -> a -> [a] -> Zipper a
Zipper ([a] -> Maybe [a] -> [a]
forall a. a -> Maybe a -> a
fromMaybe [] (Maybe [a] -> [a]) -> Maybe [a] -> [a]
forall a b. (a -> b) -> a -> b
$ [a] -> Maybe [a]
forall a. [a] -> Maybe [a]
tailMay [a]
ps) a
newCurr (a
curr a -> [a] -> [a]
forall a. a -> [a] -> [a]
: [a]
ns)

-- | Move the current focus of the cursor to the right
--
-- >>> right . fromNonEmpty $ NE.fromList [1, 2, 3]
-- Just (Zipper [1] 2 [3])
right :: Zipper a -> Maybe (Zipper a)
right :: forall a. Zipper a -> Maybe (Zipper a)
right (Zipper [a]
ps a
curr [a]
ns) = do
  a
newCurr <- [a] -> Maybe a
forall a. [a] -> Maybe a
headMay [a]
ns
  Zipper a -> Maybe (Zipper a)
forall a. a -> Maybe a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Zipper a -> Maybe (Zipper a)) -> Zipper a -> Maybe (Zipper a)
forall a b. (a -> b) -> a -> b
$ [a] -> a -> [a] -> Zipper a
forall a. [a] -> a -> [a] -> Zipper a
Zipper (a
curr a -> [a] -> [a]
forall a. a -> [a] -> [a]
: [a]
ps) a
newCurr ([a] -> Maybe [a] -> [a]
forall a. a -> Maybe a -> a
fromMaybe [] (Maybe [a] -> [a]) -> Maybe [a] -> [a]
forall a b. (a -> b) -> a -> b
$ [a] -> Maybe [a]
forall a. [a] -> Maybe [a]
tailMay [a]
ns)

-- | Move the current focus of the cursor some distance to the left
--
-- Returns 'Nothing' if the requested movement distance is too great
-- and the cursor falls off the left end of the zipper.
--
-- >>> leftN 2 . fromNonEmptyEnd $ NE.fromList [1..7]
-- Just (Zipper [4,3,2,1] 5 [6,7])
leftN :: Word -> Zipper a -> Maybe (Zipper a)
leftN :: forall a. Word -> Zipper a -> Maybe (Zipper a)
leftN = (Zipper a -> Maybe (Zipper a))
-> Word -> Zipper a -> Maybe (Zipper a)
forall (f :: * -> *) a. Monad f => (a -> f a) -> Word -> a -> f a
repeatedly Zipper a -> Maybe (Zipper a)
forall a. Zipper a -> Maybe (Zipper a)
left

-- | Move the current focus of the cursor some distance to the right
--
-- Returns 'Nothing' if the requested movement distance is too great
-- and the cursor falls off the right end of the zipper.
--
-- >>> rightN 2 . fromNonEmpty $ NE.fromList [1..7]
-- Just (Zipper [2,1] 3 [4,5,6,7])
rightN :: Word -> Zipper a -> Maybe (Zipper a)
rightN :: forall a. Word -> Zipper a -> Maybe (Zipper a)
rightN = (Zipper a -> Maybe (Zipper a))
-> Word -> Zipper a -> Maybe (Zipper a)
forall (f :: * -> *) a. Monad f => (a -> f a) -> Word -> a -> f a
repeatedly Zipper a -> Maybe (Zipper a)
forall a. Zipper a -> Maybe (Zipper a)
right

repeatedly :: Monad f => (a -> f a) -> Word -> a -> f a
repeatedly :: forall (f :: * -> *) a. Monad f => (a -> f a) -> Word -> a -> f a
repeatedly a -> f a
f Word
n a
x = (a -> Word -> f a) -> a -> [Word] -> f a
forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m b
foldM (f a -> Word -> f a
forall a b. a -> b -> a
const (f a -> Word -> f a) -> (a -> f a) -> a -> Word -> f a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> f a
f) a
x [Word
1 .. Word
n]

-- | Move the current focus of the cursor to the first occurrence of a value on the left
--
-- >>> findLeft 2 . fromNonEmptyEnd $ NE.fromList [2, 1, 2, 1, 1, 3]
-- Just (Zipper [1,2] 2 [1,1,3])
findLeft :: Eq a => a -> Zipper a -> Maybe (Zipper a)
findLeft :: forall a. Eq a => a -> Zipper a -> Maybe (Zipper a)
findLeft a
target z :: Zipper a
z@(Zipper [a]
ps a
curr [a]
ns)
  | a
curr a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
target = Zipper a -> Maybe (Zipper a)
forall a. a -> Maybe a
Just Zipper a
z
  | Bool
otherwise = case [a]
ps of
      [] -> Maybe (Zipper a)
forall a. Maybe a
Nothing
      (a
x : [a]
xs) -> a -> Zipper a -> Maybe (Zipper a)
forall a. Eq a => a -> Zipper a -> Maybe (Zipper a)
findLeft a
target ([a] -> a -> [a] -> Zipper a
forall a. [a] -> a -> [a] -> Zipper a
Zipper [a]
xs a
x (a
curr a -> [a] -> [a]
forall a. a -> [a] -> [a]
: [a]
ns))

-- | Move the current focus of the cursor to the first occurrence of a value on the right
--
-- >>> findRight 3 . fromNonEmpty $ NE.fromList [2, 1, 3, 1, 1, 3]
-- Just (Zipper [1,2] 3 [1,1,3])
findRight :: Eq a => a -> Zipper a -> Maybe (Zipper a)
findRight :: forall a. Eq a => a -> Zipper a -> Maybe (Zipper a)
findRight a
target z :: Zipper a
z@(Zipper [a]
ps a
curr [a]
ns)
  | a
curr a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
target = Zipper a -> Maybe (Zipper a)
forall a. a -> Maybe a
Just Zipper a
z
  | Bool
otherwise = case [a]
ns of
      [] -> Maybe (Zipper a)
forall a. Maybe a
Nothing
      (a
x : [a]
xs) -> a -> Zipper a -> Maybe (Zipper a)
forall a. Eq a => a -> Zipper a -> Maybe (Zipper a)
findRight a
target ([a] -> a -> [a] -> Zipper a
forall a. [a] -> a -> [a] -> Zipper a
Zipper (a
curr a -> [a] -> [a]
forall a. a -> [a] -> [a]
: [a]
ps) a
x [a]
xs)

-- | Move the current focus of the cursor to the start of the @'Zipper'@
--
-- >>> start . fromNonEmptyEnd $ NE.fromList [1, 2, 3]
-- Zipper [] 1 [2,3]
start :: Zipper a -> Zipper a
start :: forall a. Zipper a -> Zipper a
start Zipper a
z
  | Zipper a -> Bool
forall a. Zipper a -> Bool
isStart Zipper a
z = Zipper a
z
  | Bool
otherwise = NonEmpty a -> Zipper a
forall a. NonEmpty a -> Zipper a
fromNonEmpty (NonEmpty a -> Zipper a) -> NonEmpty a -> Zipper a
forall a b. (a -> b) -> a -> b
$ Zipper a -> NonEmpty a
forall a. Zipper a -> NonEmpty a
toNonEmpty Zipper a
z

-- | Move the current focus of the cursor to the end of the @'Zipper'@
--
-- >>> end . fromNonEmpty $ NE.fromList [1, 2, 3]
-- Zipper [2,1] 3 []
end :: Zipper a -> Zipper a
end :: forall a. Zipper a -> Zipper a
end Zipper a
z
  | Zipper a -> Bool
forall a. Zipper a -> Bool
isEnd Zipper a
z = Zipper a
z
  | Bool
otherwise = NonEmpty a -> Zipper a
forall a. NonEmpty a -> Zipper a
fromNonEmptyEnd (NonEmpty a -> Zipper a) -> NonEmpty a -> Zipper a
forall a b. (a -> b) -> a -> b
$ Zipper a -> NonEmpty a
forall a. Zipper a -> NonEmpty a
toNonEmpty Zipper a
z

fromNonEmpty :: NE.NonEmpty a -> Zipper a
fromNonEmpty :: forall a. NonEmpty a -> Zipper a
fromNonEmpty NonEmpty a
ne = [a] -> a -> [a] -> Zipper a
forall a. [a] -> a -> [a] -> Zipper a
Zipper [] (NonEmpty a -> a
forall a. NonEmpty a -> a
NE.head NonEmpty a
ne) (NonEmpty a -> [a]
forall a. NonEmpty a -> [a]
NE.tail NonEmpty a
ne)

fromNonEmptyEnd :: NE.NonEmpty a -> Zipper a
fromNonEmptyEnd :: forall a. NonEmpty a -> Zipper a
fromNonEmptyEnd NonEmpty a
ne = [a] -> a -> [a] -> Zipper a
forall a. [a] -> a -> [a] -> Zipper a
Zipper (NonEmpty a -> [a]
forall a. NonEmpty a -> [a]
NE.tail NonEmpty a
reversed) (NonEmpty a -> a
forall a. NonEmpty a -> a
NE.head NonEmpty a
reversed) []
 where
  reversed :: NonEmpty a
reversed = NonEmpty a -> NonEmpty a
forall a. NonEmpty a -> NonEmpty a
NE.reverse NonEmpty a
ne

toNonEmpty :: Zipper a -> NE.NonEmpty a
toNonEmpty :: forall a. Zipper a -> NonEmpty a
toNonEmpty (Zipper [a]
ls a
x [a]
rs) = [a] -> NonEmpty a
forall a. HasCallStack => [a] -> NonEmpty a
NE.fromList ([a] -> NonEmpty a) -> [a] -> NonEmpty a
forall a b. (a -> b) -> a -> b
$ [a] -> [a]
forall a. [a] -> [a]
Prelude.reverse [a]
ls [a] -> [a] -> [a]
forall a. [a] -> [a] -> [a]
++ [a
x] [a] -> [a] -> [a]
forall a. [a] -> [a] -> [a]
++ [a]
rs

-- | Replace the current item under the cursor
--
-- >>> replace 4 . fromNonEmpty $ NE.fromList [1, 2, 3]
-- Zipper [] 4 [2,3]
replace :: a -> Zipper a -> Zipper a
replace :: forall a. a -> Zipper a -> Zipper a
replace a
x (Zipper [a]
ls a
_ [a]
rs) = [a] -> a -> [a] -> Zipper a
forall a. [a] -> a -> [a] -> Zipper a
Zipper [a]
ls a
x [a]
rs

-- | Delete the item currently under the cursor
--
-- The item currently under the cursor is removed. The cursors focus will move
-- right. If at the end of the @'Zipper'@ the cursor will move left.
--
-- >>> delete . fromNonEmpty $ NE.fromList [1, 2, 3]
-- Just (Zipper [] 2 [3])
--
-- >>> delete . fromNonEmptyEnd $ NE.fromList [1, 2, 3]
-- Just (Zipper [1] 2 [])
delete :: Zipper a -> Maybe (Zipper a)
delete :: forall a. Zipper a -> Maybe (Zipper a)
delete (Zipper [] a
_ []) = Maybe (Zipper a)
forall a. Maybe a
Nothing
delete (Zipper [a]
ls a
_ (a
r : [a]
rs)) = Zipper a -> Maybe (Zipper a)
forall a. a -> Maybe a
Just (Zipper a -> Maybe (Zipper a)) -> Zipper a -> Maybe (Zipper a)
forall a b. (a -> b) -> a -> b
$ [a] -> a -> [a] -> Zipper a
forall a. [a] -> a -> [a] -> Zipper a
Zipper [a]
ls a
r [a]
rs
delete (Zipper (a
l : [a]
ls) a
_ [a]
rs) = Zipper a -> Maybe (Zipper a)
forall a. a -> Maybe a
Just (Zipper a -> Maybe (Zipper a)) -> Zipper a -> Maybe (Zipper a)
forall a b. (a -> b) -> a -> b
$ [a] -> a -> [a] -> Zipper a
forall a. [a] -> a -> [a] -> Zipper a
Zipper [a]
ls a
l [a]
rs

-- | Insert a value to the left of the cursor
--
-- >>> push 0 . fromNonEmpty $ NE.fromList [1, 2, 3]
-- Zipper [0] 1 [2,3]
push :: a -> Zipper a -> Zipper a
push :: forall a. a -> Zipper a -> Zipper a
push a
l (Zipper [a]
ls a
x [a]
rs) = [a] -> a -> [a] -> Zipper a
forall a. [a] -> a -> [a] -> Zipper a
Zipper (a
l a -> [a] -> [a]
forall a. a -> [a] -> [a]
: [a]
ls) a
x [a]
rs

-- | Remove a value to the left of the cursor
--
-- >>> pop . fromNonEmpty $ NE.fromList [1, 2, 3]
-- (Zipper [] 1 [2,3],Nothing)
--
-- >>> pop . fromNonEmptyEnd $ NE.fromList [1, 2, 3]
-- (Zipper [1] 3 [],Just 2)
pop :: Zipper a -> (Zipper a, Maybe a)
pop :: forall a. Zipper a -> (Zipper a, Maybe a)
pop (Zipper [] a
x [a]
rs) = ([a] -> a -> [a] -> Zipper a
forall a. [a] -> a -> [a] -> Zipper a
Zipper [] a
x [a]
rs, Maybe a
forall a. Maybe a
Nothing)
pop (Zipper (a
l : [a]
ls) a
x [a]
rs) = ([a] -> a -> [a] -> Zipper a
forall a. [a] -> a -> [a] -> Zipper a
Zipper [a]
ls a
x [a]
rs, a -> Maybe a
forall a. a -> Maybe a
Just a
l)

-- | Remove a value to the right of the cursor
--
-- >>> shift . fromNonEmptyEnd $ NE.fromList [1, 2, 3]
-- (Zipper [2,1] 3 [],Nothing)
--
-- >>> shift . fromNonEmpty $ NE.fromList [1, 2, 3]
-- (Zipper [] 1 [3],Just 2)
shift :: Zipper a -> (Zipper a, Maybe a)
shift :: forall a. Zipper a -> (Zipper a, Maybe a)
shift (Zipper [a]
ls a
x []) = ([a] -> a -> [a] -> Zipper a
forall a. [a] -> a -> [a] -> Zipper a
Zipper [a]
ls a
x [], Maybe a
forall a. Maybe a
Nothing)
shift (Zipper [a]
ls a
x (a
r : [a]
rs)) = ([a] -> a -> [a] -> Zipper a
forall a. [a] -> a -> [a] -> Zipper a
Zipper [a]
ls a
x [a]
rs, a -> Maybe a
forall a. a -> Maybe a
Just a
r)

-- | Insert a value to the right of the cursor
--
-- >>> unshift 4 . fromNonEmpty $ NE.fromList [1, 2, 3]
-- Zipper [] 1 [4,2,3]
unshift :: a -> Zipper a -> Zipper a
unshift :: forall a. a -> Zipper a -> Zipper a
unshift a
r (Zipper [a]
ls a
x [a]
rs) = [a] -> a -> [a] -> Zipper a
forall a. [a] -> a -> [a] -> Zipper a
Zipper [a]
ls a
x (a
r a -> [a] -> [a]
forall a. a -> [a] -> [a]
: [a]
rs)

-- | Reverse the zipper keeping the cursor focus intact
--
-- >>> reverse . fromNonEmpty $ NE.fromList [1, 2, 3]
-- Zipper [2,3] 1 []
reverse :: Zipper a -> Zipper a
reverse :: forall a. Zipper a -> Zipper a
reverse (Zipper [a]
ls a
x [a]
rs) = [a] -> a -> [a] -> Zipper a
forall a. [a] -> a -> [a] -> Zipper a
Zipper [a]
rs a
x [a]
ls

-- | Determine if the @'Zipper'@ is at the beginning
--
-- >>> isStart . fromNonEmpty $ NE.fromList [1, 2, 3]
-- True
--
-- >>> isStart . fromNonEmptyEnd $ NE.fromList [1, 2, 3]
-- False
isStart :: Zipper a -> Bool
isStart :: forall a. Zipper a -> Bool
isStart (Zipper [] a
_ [a]
_) = Bool
True
isStart Zipper a
_ = Bool
False

-- | Determine if the @'Zipper'@ is at the end
--
-- >>> isEnd . fromNonEmptyEnd $ NE.fromList [1, 2, 3]
-- True
--
-- >>> isEnd . fromNonEmpty $ NE.fromList [1, 2, 3]
-- False
isEnd :: Zipper a -> Bool
isEnd :: forall a. Zipper a -> Bool
isEnd (Zipper [a]
_ a
_ []) = Bool
True
isEnd Zipper a
_ = Bool
False