packages feed

nonempty-zipper 1.0.0.4 → 1.0.1.0

raw patch · 3 files changed

+59/−53 lines, 3 filesdep ~Globdep ~basedep ~comonad

Dependency ranges changed: Glob, base, comonad, deepseq, safe

Files

CHANGELOG.md view
@@ -1,6 +1,8 @@-## [_Unreleased_](https://github.com/freckle/nonempty-zipper/compare/v1.0.0.4...main)+## [_Unreleased_](https://github.com/freckle/nonempty-zipper/compare/v1.0.1.0...main) -None+## [v1.0.1.0](https://github.com/freckle/nonempty-zipper/compare/v1.0.0.4...v1.0.1.0)++- Add `leftN` and `rightN`  ## [v1.0.0.4](https://github.com/freckle/nonempty-zipper/compare/v1.0.0.3...v1.0.0.4) 
library/Data/List/NonEmpty/Zipper.hs view
@@ -6,24 +6,26 @@ module Data.List.NonEmpty.Zipper   ( Zipper -  -- * Accessors+    -- * Accessors   , lefts   , rights   , current -  -- * Traversal+    -- * Traversal   , left   , right+  , leftN+  , rightN   , findLeft   , findRight   , start   , end -  -- * Construction+    -- * Construction   , fromNonEmpty   , fromNonEmptyEnd -  -- ** Update+    -- ** Update   , replace   , delete   , push@@ -32,7 +34,7 @@   , unshift   , reverse -  -- * Predicates+    -- * Predicates   , isStart   , isEnd   )@@ -43,6 +45,7 @@  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)@@ -69,18 +72,17 @@ -- -- >>> 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 = current   duplicate z =     let dupWith f r =           case f r of             Nothing -> [r]-            Just x -> r:dupWith f x-    in Zipper-      (maybe [] (dupWith left) $ left z)-      z-      (maybe [] (dupWith right) $ right z)+            Just x -> r : dupWith f x+    in  Zipper+          (maybe [] (dupWith left) $ left z)+          z+          (maybe [] (dupWith right) $ right z)  -- | Get the current focus of the @'Zipper'@ cursor --@@ -88,7 +90,6 @@ -- -- >>> current . fromNonEmpty $ NE.fromList [1, 2, 3] -- 1--- current :: Zipper a -> a current (Zipper _ curr _) = curr @@ -96,7 +97,6 @@ -- -- >>> lefts . fromNonEmptyEnd $ NE.fromList [1, 2, 3] -- [1,2]--- lefts :: Zipper a -> [a] lefts (Zipper ls _ _) = Prelude.reverse ls @@ -104,16 +104,13 @@ -- -- >>> rights . fromNonEmpty $ NE.fromList [1, 2, 3] -- [2,3]--- rights :: Zipper a -> [a] rights (Zipper _ _ rs) = 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 (Zipper ps curr ns) = do   newCurr <- headMay ps@@ -123,41 +120,60 @@ -- -- >>> right . fromNonEmpty $ NE.fromList [1, 2, 3] -- Just (Zipper [1] 2 [3])--- right :: Zipper a -> Maybe (Zipper a) right (Zipper ps curr ns) = do   newCurr <- headMay ns   pure $ Zipper (curr : ps) newCurr (fromMaybe [] $ tailMay ns) --- | Move the current focus of the cursor to the first occurence of a value on the left+-- | 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 = repeatedly 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 = repeatedly right++repeatedly :: Monad f => (a -> f a) -> Word -> a -> f a+repeatedly f n x = foldM (const . f) x [1 .. 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 target z@(Zipper ps curr ns)   | curr == target = Just z   | otherwise = case ps of-    [] -> Nothing-    (x : xs) -> findLeft target (Zipper xs x (curr : ns))+      [] -> Nothing+      (x : xs) -> findLeft target (Zipper xs x (curr : ns)) --- | Move the current focus of the cursor to the first occurence of a value on the right+-- | 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 target z@(Zipper ps curr ns)   | curr == target = Just z   | otherwise = case ns of-    [] -> Nothing-    (x : xs) -> findRight target (Zipper (curr : ps) x xs)+      [] -> Nothing+      (x : xs) -> findRight target (Zipper (curr : ps) x 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 z   | isStart z = z@@ -167,29 +183,26 @@ -- -- >>> end . fromNonEmpty $ NE.fromList [1, 2, 3] -- Zipper [2,1] 3 []--- end :: Zipper a -> Zipper a end z   | isEnd z = z   | otherwise = fromNonEmptyEnd $ toNonEmpty z - fromNonEmpty :: NE.NonEmpty a -> Zipper a fromNonEmpty ne = Zipper [] (NE.head ne) (NE.tail ne)  fromNonEmptyEnd :: NE.NonEmpty a -> Zipper a fromNonEmptyEnd ne = Zipper (NE.tail reversed) (NE.head reversed) []-  where reversed = NE.reverse ne+ where+  reversed = NE.reverse ne  toNonEmpty :: Zipper a -> NE.NonEmpty a toNonEmpty (Zipper ls x rs) = NE.fromList $ Prelude.reverse ls ++ [x] ++ rs ---- | Replace the current item under the curosr+-- | 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 x (Zipper ls _ rs) = Zipper ls x rs @@ -203,7 +216,6 @@ -- -- >>> delete . fromNonEmptyEnd $ NE.fromList [1, 2, 3] -- Just (Zipper [1] 2 [])--- delete :: Zipper a -> Maybe (Zipper a) delete (Zipper [] _ []) = Nothing delete (Zipper ls _ (r : rs)) = Just $ Zipper ls r rs@@ -213,7 +225,6 @@ -- -- >>> push 0 . fromNonEmpty $ NE.fromList [1, 2, 3] -- Zipper [0] 1 [2,3]--- push :: a -> Zipper a -> Zipper a push l (Zipper ls x rs) = Zipper (l : ls) x rs @@ -224,7 +235,6 @@ -- -- >>> pop . fromNonEmptyEnd $ NE.fromList [1, 2, 3] -- (Zipper [1] 3 [],Just 2)--- pop :: Zipper a -> (Zipper a, Maybe a) pop (Zipper [] x rs) = (Zipper [] x rs, Nothing) pop (Zipper (l : ls) x rs) = (Zipper ls x rs, Just l)@@ -236,7 +246,6 @@ -- -- >>> shift . fromNonEmpty $ NE.fromList [1, 2, 3] -- (Zipper [] 1 [3],Just 2)--- shift :: Zipper a -> (Zipper a, Maybe a) shift (Zipper ls x []) = (Zipper ls x [], Nothing) shift (Zipper ls x (r : rs)) = (Zipper ls x rs, Just r)@@ -245,7 +254,6 @@ -- -- >>> unshift 4 . fromNonEmpty $ NE.fromList [1, 2, 3] -- Zipper [] 1 [4,2,3]--- unshift :: a -> Zipper a -> Zipper a unshift r (Zipper ls x rs) = Zipper ls x (r : rs) @@ -253,11 +261,9 @@ -- -- >>> reverse . fromNonEmpty $ NE.fromList [1, 2, 3] -- Zipper [2,3] 1 []--- reverse :: Zipper a -> Zipper a reverse (Zipper ls x rs) = Zipper rs x ls - -- | Determine if the @'Zipper'@ is at the beginning -- -- >>> isStart . fromNonEmpty $ NE.fromList [1, 2, 3]@@ -265,7 +271,6 @@ -- -- >>> isStart . fromNonEmptyEnd $ NE.fromList [1, 2, 3] -- False--- isStart :: Zipper a -> Bool isStart (Zipper [] _ _) = True isStart _ = False@@ -277,7 +282,6 @@ -- -- >>> isEnd . fromNonEmpty $ NE.fromList [1, 2, 3] -- False--- isEnd :: Zipper a -> Bool isEnd (Zipper _ _ []) = True isEnd _ = False
nonempty-zipper.cabal view
@@ -1,6 +1,6 @@ cabal-version:      1.12 name:               nonempty-zipper-version:            1.0.0.4+version:            1.0.1.0 license:            MIT license-file:       LICENSE copyright:          2021 Renaissance Learning Inc@@ -27,10 +27,10 @@     default-language: Haskell2010     ghc-options:      -Wall     build-depends:-        base >=4.11.1.0 && <5,-        comonad >=5.0.4,-        deepseq >=1.4.3.0,-        safe >=0.3.17+        base >=4.19.2.0 && <5,+        comonad >=5.0.9,+        deepseq >=1.5.1.0,+        safe >=0.3.21  test-suite doctest     type:             exitcode-stdio-1.0@@ -40,9 +40,9 @@     default-language: Haskell2010     ghc-options:      -Wall     build-depends:-        Glob >=0.9.3,-        base >=4.11.1.0 && <5,-        comonad >=5.0.4,-        deepseq >=1.4.3.0,+        Glob >=0.10.2,+        base >=4.19.2.0 && <5,+        comonad >=5.0.9,+        deepseq >=1.5.1.0,         doctest >0.16,-        safe >=0.3.17+        safe >=0.3.21