focuslist 0.1.0.2 → 0.1.1.0
raw patch · 7 files changed
+141/−12 lines, 7 filesdep +genvaliditydep +hspecdep +validityPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: genvalidity, hspec, validity
API changes (from Hackage documentation)
+ Data.FocusList: setFocusItemFL :: a -> FocusList a -> FocusList a
+ Data.FocusList: traversalFocusItem :: forall a. Traversal' (FocusList a) a
+ Data.FocusList: updateFocusItemFL :: (a -> a) -> FocusList a -> FocusList a
- Data.FocusList: lensFocusList :: forall a_af3x a_akrU. Lens (FocusList a_af3x) (FocusList a_akrU) (Seq a_af3x) (Seq a_akrU)
+ Data.FocusList: lensFocusList :: forall a_aac2 a_acvF. Lens (FocusList a_aac2) (FocusList a_acvF) (Seq a_aac2) (Seq a_acvF)
- Data.FocusList: lensFocusListFocus :: forall a_af3x. Lens' (FocusList a_af3x) Focus
+ Data.FocusList: lensFocusListFocus :: forall a_aac2. Lens' (FocusList a_aac2) Focus
Files
- CHANGELOG.md +5/−0
- README.md +1/−1
- focuslist.cabal +10/−1
- src/Data/FocusList.hs +122/−7
- test/Test/FocusList.hs +2/−1
- test/Test/FocusList/Invariants.hs +0/−1
- test/readme/README.lhs +1/−1
CHANGELOG.md view
@@ -2,6 +2,11 @@ ## Unreleased changes +## v0.1.1.0++- Add functions `updateFocusItemFL`, `setFocusItemFL`, and `traversalFocusItem`.+ [#13](https://github.com/cdepillabout/focuslist/pull/13).+ ## v0.1.0.2 - Update to allow the latest version of genvalidity
README.md view
@@ -11,7 +11,7 @@ supports quick insertion and indexing by its implementation with [`Seq`](http://hackage.haskell.org/package/containers-0.6.0.1/docs/Data-Sequence.html#t:Seq). -The fcuslist package is similar to [pointed-list](http://hackage.haskell.org/package/pointedlist-0.6.1) or [list-zipper](http://hackage.haskell.org/package/ListZipper). Focuslist however is optimised for fast indexing and insertion at any point, and can be empty. For operations where linked lists perform better the other packages are likely to be superior, though for other operations focuslist is likely to be faster.+The focuslist package is similar to [pointed-list](http://hackage.haskell.org/package/pointedlist-0.6.1) or [list-zipper](http://hackage.haskell.org/package/ListZipper). Focuslist however is optimised for fast indexing and insertion at any point, and can be empty. For operations where linked lists perform better the other packages are likely to be superior, though for other operations focuslist is likely to be faster. ## Example
focuslist.cabal view
@@ -1,5 +1,5 @@ name: focuslist-version: 0.1.0.2+version: 0.1.1.0 synopsis: Lists with a focused element description: Please see <https://github.com/cdepillabout/focuslist#readme README.md>. homepage: https://github.com/cdepillabout/focuslist@@ -57,14 +57,23 @@ , Test.FocusList.Invariants build-depends: base , focuslist+ -- genvalidity >= 1.0.0.0 makes some big changes, like+ -- dropping the GenInvalid and GenUnchecked classes, as+ -- well as changing the default implementation of methods+ -- in the GenValid class.+ , genvalidity < 1.0.0.0 , genvalidity-containers >= 0.5 , genvalidity-hspec >= 0.6 , hedgehog >= 0.6.1+ , hspec , lens , QuickCheck , tasty >= 1.1 , tasty-hedgehog >= 0.2 , tasty-hspec >= 1.1+ -- See note above about genvalidity. genvalidity+ -- doesn't have correct lower bounds on validity.+ , validity < 0.12.0.0 default-language: Haskell2010 ghc-options: -Wall -Wincomplete-uni-patterns -Wincomplete-record-updates -threaded -rtsopts -with-rtsopts=-N
src/Data/FocusList.hs view
@@ -35,6 +35,10 @@ , moveFromToFL , intersperseFL , reverseFL+ , updateFocusItemFL+ , setFocusItemFL+ , -- *** Optics+ traversalFocusItem -- *** Manipulate 'Focus' , setFocusFL , updateFocusFL@@ -60,10 +64,10 @@ , lensFocusList -- * Focus , Focus(Focus, NoFocus)- , hasFocus- , getFocus- , maybeToFocus- , foldFocus+ , hasFocus+ , getFocus+ , maybeToFocus+ , foldFocus -- ** Optics , _Focus , _NoFocus@@ -73,12 +77,11 @@ import Prelude hiding (reverse) -import Control.Lens (Prism', (^.), (.~), (-~), makeLensesFor, prism')+import Control.Lens (Prism', Traversal', (^.), (.~), (-~), makeLensesFor, prism') import Data.Foldable (toList) import Data.Function ((&)) import Data.MonoTraversable (Element, GrowingAppend, MonoFoldable, MonoFunctor, MonoTraversable, olength)-import Data.Semigroup ((<>)) import qualified Data.Sequence as Sequence import Data.Sequence (Seq((:<|), Empty), (<|), deleteAt, elemIndexL, insertAt, singleton)@@ -90,12 +93,12 @@ ( Arbitrary, Arbitrary1, CoArbitrary, Gen, arbitrary, arbitrary1, choose , frequency, liftArbitrary )-import Text.Show (Show(showsPrec), ShowS, showParen, showString) -- $setup -- >>> :set -XFlexibleContexts -- >>> :set -XScopedTypeVariables -- >>> import Data.Maybe (isJust)+-- >>> import Control.Lens ((^..)) -- | A 'Focus' for the 'FocusList'. --@@ -139,10 +142,24 @@ foldFocus _ f (Focus i) = f i -- | A 'Prism'' for focusing on the 'Focus' constructor in a 'Focus' data type.+--+-- You can use this to get the 'Int' that is being focused on:+--+-- >>> import Control.Lens ((^?))+-- >>> Focus 100 ^? _Focus+-- Just 100+-- >>> NoFocus ^? _Focus+-- Nothing _Focus :: Prism' Focus Int _Focus = prism' Focus (foldFocus Nothing Just) -- | A 'Prism'' for focusing on the 'NoFocus' constructor in a 'Focus' data type.+--+-- >>> import Control.Lens.Extras (is)+-- >>> is _NoFocus NoFocus+-- True+-- >>> is _NoFocus (Focus 3)+-- False _NoFocus :: Prism' Focus () _NoFocus = prism' (const NoFocus) (foldFocus (Just ()) (const Nothing)) @@ -226,6 +243,44 @@ ''FocusList ) +-- | A 'Traversal' for the focused item in a 'FocusList'.+--+-- This can be used to get the focused item:+--+-- >>> import Control.Lens ((^?))+-- >>> let Just fl = fromListFL (Focus 1) ["hello", "bye", "tree"]+-- >>> fl ^? traversalFocusItem+-- Just "bye"+-- >>> emptyFL ^? traversalFocusItem+-- Nothing+--+-- This can also be used to set the focused item:+--+-- >>> import Control.Lens (set)+-- >>> let Just fl = fromListFL (Focus 1) ["hello", "bye", "tree"]+-- >>> set traversalFocusItem "new val" fl+-- FocusList (Focus 1) ["hello","new val","tree"]+-- >>> set traversalFocusItem "new val" emptyFL+-- FocusList NoFocus []+--+-- Note that this traversal will apply to no elements if the 'FocusList' is+-- empty and 'NoFocus'. This traversal will apply to a single element if the+-- 'FocusList' has a 'Focus'. This makes 'traversalFocusItem' an affine traversal.+--+-- prop> length (fl ^.. traversalFocusItem) <= 1+traversalFocusItem :: forall a. Traversal' (FocusList a) a+traversalFocusItem f fl@FocusList {focusListFocus, focusList} =+ case focusListFocus of+ NoFocus -> pure fl+ Focus focus ->+ case Sequence.lookup focus focusList of+ Nothing ->+ error $+ "traersalFLItem: internal error, focus (" <>+ show focus <>+ ") doesnt exist in sequence"+ Just a -> fmap (\a' -> setFocusItemFL a' fl) (f a)+ instance Foldable FocusList where foldr f b (FocusList _ fls) = foldr f b fls @@ -676,6 +731,66 @@ show i <> ") doesnt exist in sequence" Just a -> Just a++-- | Set the item the 'FocusList' is focusing on.+--+-- >>> let Just fl = fromListFL (Focus 1) [10, 20, 30]+-- >>> setFocusItemFL 0 fl+-- FocusList (Focus 1) [10,0,30]+--+-- >>> setFocusItemFL "hello" emptyFL+-- FocusList NoFocus []+--+-- Note: this function forces the updated item. The following throws an+-- exception from 'undefined' even though we updated the focused item at index+-- 1, but lookup the item at index 0.+--+-- >>> let Just fl = fromListFL (Focus 1) [10, 20, 30]+-- >>> let newFl = setFocusItemFL undefined fl+-- >>> lookupFL 0 newFl+-- *** Exception: ...+-- ...+--+-- This is a specialization of 'updateFocusItemFL':+--+-- prop> updateFocusItemFL (const a) fl == setFocusItemFL a fl+--+-- /complexity/: @O(log(min(i, n - i)))@ where @i@ is the 'Focus', and @n@+-- is the length of the 'FocusList'.+setFocusItemFL :: a -> FocusList a -> FocusList a+setFocusItemFL a fl = updateFocusItemFL (const a) fl++-- | Update the item the 'FocusList' is focusing on. Do nothing if+-- the 'FocusList' is empty.+--+-- >>> let Just fl = fromListFL (Focus 1) [10, 20, 30]+-- >>> updateFocusItemFL (\a -> a + 5) fl+-- FocusList (Focus 1) [10,25,30]+--+-- >>> updateFocusItemFL (\a -> a * 100) emptyFL+-- FocusList NoFocus []+--+-- Note: this function forces the updated item. The following throws an+-- exception from 'undefined' even though we updated the focused item at index+-- 1, but lookup the item at index 0.+--+-- >>> let Just fl = fromListFL (Focus 1) [10, 20, 30]+-- >>> let newFl = updateFocusItemFL (const undefined) fl+-- >>> lookupFL 0 newFl+-- *** Exception: ...+-- ...+--+-- /complexity/: @O(log(min(i, n - i)))@ where @i@ is the 'Focus', and @n@+-- is the length of the 'FocusList'.+updateFocusItemFL :: (a -> a) -> FocusList a -> FocusList a+updateFocusItemFL f fl =+ let focus = fl ^. lensFocusListFocus+ in+ case focus of+ NoFocus -> fl+ Focus i ->+ let fls = fl ^. lensFocusList+ in fl { focusList = Sequence.adjust' f i fls } -- | Lookup the element at the specified index, counting from 0. --
test/Test/FocusList.hs view
@@ -5,10 +5,11 @@ module Test.FocusList where import Data.GenValidity.Sequence ()+import Test.Hspec (Spec) import Test.QuickCheck (Gen) import Test.Tasty (TestTree, testGroup) import Test.Tasty.Hedgehog (testProperty)-import Test.Tasty.Hspec (Spec, testSpec)+import Test.Tasty.Hspec (testSpec) import Test.Validity (GenInvalid, GenUnchecked, GenValid(genValid), Validity(validate), check, eqSpec, genValidSpec) import Data.FocusList (Focus, FocusList, genValidFL, invariantFL)
test/Test/FocusList/Invariants.hs view
@@ -2,7 +2,6 @@ module Test.FocusList.Invariants where import Data.Maybe (catMaybes)-import Data.Semigroup ((<>)) import Hedgehog ( Gen , Property
test/readme/README.lhs view
@@ -11,7 +11,7 @@ supports quick insertion and indexing by its implementation with [`Seq`](http://hackage.haskell.org/package/containers-0.6.0.1/docs/Data-Sequence.html#t:Seq). -The fcuslist package is similar to [pointed-list](http://hackage.haskell.org/package/pointedlist-0.6.1) or [list-zipper](http://hackage.haskell.org/package/ListZipper). Focuslist however is optimised for fast indexing and insertion at any point, and can be empty. For operations where linked lists perform better the other packages are likely to be superior, though for other operations focuslist is likely to be faster.+The focuslist package is similar to [pointed-list](http://hackage.haskell.org/package/pointedlist-0.6.1) or [list-zipper](http://hackage.haskell.org/package/ListZipper). Focuslist however is optimised for fast indexing and insertion at any point, and can be empty. For operations where linked lists perform better the other packages are likely to be superior, though for other operations focuslist is likely to be faster. ## Example