packages feed

focus 1.0.3 → 1.0.3.1

raw patch · 5 files changed

+353/−369 lines, 5 filesdep −QuickCheckdep −quickcheck-instancesdep −tasty-quickcheckdep ~basedep ~transformerssetup-changedPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies removed: QuickCheck, quickcheck-instances, tasty-quickcheck

Dependency ranges changed: base, transformers

API changes (from Hackage documentation)

- Focus: casesM :: Monad m => m (b, Change a) -> (a -> m (b, Change a)) -> Focus a m b
+ Focus: casesM :: m (b, Change a) -> (a -> m (b, Change a)) -> Focus a m b

Files

− Setup.hs
@@ -1,2 +0,0 @@-import Distribution.Simple-main = defaultMain
focus.cabal view
@@ -1,59 +1,102 @@-name: focus-version: 1.0.3-synopsis: A general abstraction for manipulating elements of container data structures+cabal-version: 3.0+name:          focus+version:       1.0.3.1+synopsis:+  A general abstraction for manipulating elements of container data structures+ description:   An API for construction of free-form strategies of access and manipulation of    elements of arbitrary data structures.   It allows to implement efficient composite patterns, e.g.,    a simultaneous update and lookup of an element,    and even more complex things.-  .   Strategies are meant to be interpreted by the host data structure libraries.   Thus they allow to implement all access and modification patterns of   a data structure with just a single function,   which interprets strategies.-  .   This library provides pure and monadic interfaces,   so it supports both immutable and mutable data structures.-category: Containers, Data-homepage: https://github.com/nikita-volkov/focus-bug-reports: https://github.com/nikita-volkov/focus/issues-author: Nikita Volkov <nikita.y.volkov@mail.ru>-maintainer: Nikita Volkov <nikita.y.volkov@mail.ru>-copyright: (c) 2014, Nikita Volkov-license: MIT-license-file: LICENSE-build-type: Simple-cabal-version: >=1.10 +category:      Containers, Data+homepage:      https://github.com/nikita-volkov/focus+bug-reports:   https://github.com/nikita-volkov/focus/issues+author:        Nikita Volkov <nikita.y.volkov@mail.ru>+maintainer:    Nikita Volkov <nikita.y.volkov@mail.ru>+copyright:     (c) 2014, Nikita Volkov+license:       MIT+license-file:  LICENSE+ source-repository head-  type: git+  type:     git   location: git://github.com/nikita-volkov/focus.git +common language-settings+  default-extensions:+    NoImplicitPrelude+    NoMonomorphismRestriction+    ApplicativeDo+    BangPatterns+    BinaryLiterals+    BlockArguments+    ConstraintKinds+    DataKinds+    DefaultSignatures+    DeriveDataTypeable+    DeriveFoldable+    DeriveFunctor+    DeriveGeneric+    DeriveTraversable+    DerivingVia+    DuplicateRecordFields+    EmptyDataDecls+    FlexibleContexts+    FlexibleInstances+    FunctionalDependencies+    GADTs+    GeneralizedNewtypeDeriving+    HexFloatLiterals+    LambdaCase+    LiberalTypeSynonyms+    MultiParamTypeClasses+    MultiWayIf+    NumericUnderscores+    OverloadedLabels+    OverloadedStrings+    ParallelListComp+    PatternGuards+    PatternSynonyms+    QuasiQuotes+    RankNTypes+    RecordWildCards+    ScopedTypeVariables+    StandaloneDeriving+    StrictData+    TemplateHaskell+    TupleSections+    TypeApplications+    TypeFamilies+    TypeOperators+    UndecidableInstances+    ViewPatterns++  default-language:   Haskell2010+ library-  hs-source-dirs: library-  default-extensions: Arrows, BangPatterns, ConstraintKinds, DataKinds, DefaultSignatures, DeriveDataTypeable, DeriveFoldable, DeriveFunctor, DeriveGeneric, DeriveTraversable, EmptyDataDecls, FlexibleContexts, FlexibleInstances, FunctionalDependencies, GADTs, GeneralizedNewtypeDeriving, LambdaCase, LiberalTypeSynonyms, MagicHash, MultiParamTypeClasses, MultiWayIf, NoImplicitPrelude, NoMonomorphismRestriction, OverloadedLists, OverloadedStrings, PatternGuards, PatternSynonyms, ParallelListComp, QuasiQuotes, RankNTypes, RecordWildCards, ScopedTypeVariables, StandaloneDeriving, TemplateHaskell, TupleSections, TypeApplications, TypeFamilies, TypeOperators, UnboxedTuples-  default-language: Haskell2010-  exposed-modules:-    Focus-  other-modules:-    Focus.Prelude+  import:          language-settings+  hs-source-dirs:  library+  exposed-modules: Focus+  other-modules:   Focus.Prelude   build-depends:-    base >=4.11 && <5,-    transformers >=0.5 && <0.6+    , base >=4.11 && <5+    , transformers >=0.5 && <0.7  test-suite test-  type: exitcode-stdio-1.0+  import:         language-settings+  type:           exitcode-stdio-1.0   hs-source-dirs: test-  default-extensions: BangPatterns, DeriveDataTypeable, DeriveGeneric, DeriveFunctor, DeriveTraversable, FlexibleContexts, FlexibleInstances, LambdaCase, NoImplicitPrelude, RankNTypes, ScopedTypeVariables, StandaloneDeriving, TypeApplications, TypeFamilies-  default-language: Haskell2010-  main-is:-    Main.hs+  main-is:        Main.hs   build-depends:-    focus,-    QuickCheck >=2.8.1 && <3,-    quickcheck-instances >=0.3.11 && <0.4,-    rerebase <2,-    tasty >=0.12 && <2,-    tasty-hunit >=0.9 && <0.11,-    tasty-quickcheck >=0.9 && <0.11+    , focus+    , rerebase <2+    , tasty >=0.12 && <2+    , tasty-hunit >=0.9 && <0.11
library/Focus.hs view
@@ -1,25 +1,23 @@ module Focus where -import Focus.Prelude hiding (adjust, update, alter, insert, delete, lookup)---{-|-Abstraction over the modification of an element of a datastructure.--It is composable using the standard typeclasses, e.g.:+import Focus.Prelude hiding (delete, insert, lookup) ->lookupAndDelete :: Monad m => Focus a m (Maybe a)->lookupAndDelete = lookup <* delete--}+-- |+-- Abstraction over the modification of an element of a datastructure.+--+-- It is composable using the standard typeclasses, e.g.:+--+-- >lookupAndDelete :: Monad m => Focus a m (Maybe a)+-- >lookupAndDelete = lookup <* delete data Focus element m result = Focus (m (result, Change element)) (element -> m (result, Change element)) -deriving instance Functor m => Functor (Focus element m)+deriving instance (Functor m) => Functor (Focus element m) -instance Monad m => Applicative (Focus element m) where+instance (Monad m) => Applicative (Focus element m) where   pure a = Focus (pure (a, Leave)) (const (pure (a, Leave)))   (<*>) = ap -instance Monad m => Monad (Focus element m) where+instance (Monad m) => Monad (Focus element m) where   return = pure   (>>=) (Focus lAbsent lPresent) rk =     Focus absent present@@ -44,15 +42,17 @@ instance MonadTrans (Focus element) where   lift m = Focus (fmap (,Leave) m) (const (fmap (,Leave) m)) -{-|-What to do with the focused value.--The interpretation of the commands is up to the context APIs.--}-data Change a =-  Leave {-^ Produce no changes -} |-  Remove {-^ Delete it -} |-  Set a {-^ Set its value to the provided one -}+-- |+-- What to do with the focused value.+--+-- The interpretation of the commands is up to the context APIs.+data Change a+  = -- | Produce no changes+    Leave+  | -- | Delete it+    Remove+  | -- | Set its value to the provided one+    Set a   deriving (Functor, Eq, Ord, Show)  instance Semigroup (Change a) where@@ -64,241 +64,204 @@ instance Monoid (Change a) where   mempty = Leave - -- * Pure functions--------------------------  -- ** Reading functions-------------------------- -{-|-Reproduces the behaviour of-@Data.Map.<http://hackage.haskell.org/package/containers-0.6.0.1/docs/Data-Map-Lazy.html#v:member member>@.--}+-- |+-- Reproduces the behaviour of+-- @Data.Map.<http://hackage.haskell.org/package/containers-0.6.0.1/docs/Data-Map-Lazy.html#v:member member>@. {-# INLINE member #-}-member :: Monad m => Focus a m Bool+member :: (Monad m) => Focus a m Bool member = fmap (maybe False (const True)) lookup -{-|-Reproduces the behaviour of-@Data.Map.<http://hackage.haskell.org/package/containers-0.6.0.1/docs/Data-Map-Lazy.html#v:lookup lookup>@.--}-{-# INLINE[1] lookup #-}-lookup :: Monad m => Focus a m (Maybe a)-lookup = cases (Nothing, Leave) (\ a -> (Just a, Leave))+-- |+-- Reproduces the behaviour of+-- @Data.Map.<http://hackage.haskell.org/package/containers-0.6.0.1/docs/Data-Map-Lazy.html#v:lookup lookup>@.+{-# INLINE [1] lookup #-}+lookup :: (Monad m) => Focus a m (Maybe a)+lookup = cases (Nothing, Leave) (\a -> (Just a, Leave)) -{-|-Reproduces the behaviour of-@Data.Map.<http://hackage.haskell.org/package/containers-0.6.0.1/docs/Data-Map-Lazy.html#v:findWithDefault findWithDefault>@-with a better name.--}-{-# INLINE[1] lookupWithDefault #-}-lookupWithDefault :: Monad m => a -> Focus a m a-lookupWithDefault a = cases (a, Leave) (\ a -> (a, Leave))+-- |+-- Reproduces the behaviour of+-- @Data.Map.<http://hackage.haskell.org/package/containers-0.6.0.1/docs/Data-Map-Lazy.html#v:findWithDefault findWithDefault>@+-- with a better name.+{-# INLINE [1] lookupWithDefault #-}+lookupWithDefault :: (Monad m) => a -> Focus a m a+lookupWithDefault a = cases (a, Leave) (\a -> (a, Leave))  -- ** Modifying functions-------------------------- -{-|-Reproduces the behaviour of-@Data.Map.<http://hackage.haskell.org/package/containers-0.6.0.1/docs/Data-Map-Lazy.html#v:delete delete>@.--}-{-# INLINE[1] delete #-}-delete :: Monad m => Focus a m ()+-- |+-- Reproduces the behaviour of+-- @Data.Map.<http://hackage.haskell.org/package/containers-0.6.0.1/docs/Data-Map-Lazy.html#v:delete delete>@.+{-# INLINE [1] delete #-}+delete :: (Monad m) => Focus a m () delete = unitCases Leave (const Remove) -{-|-Lookup an element and delete it if it exists.--Same as @'lookup' <* 'delete'@.--}+-- |+-- Lookup an element and delete it if it exists.+--+-- Same as @'lookup' <* 'delete'@. {-# RULES-  "lookup <* delete" [~1] lookup <* delete = lookupAndDelete+"lookup <* delete" [~1] lookup <* delete = lookupAndDelete   #-}+ {-# INLINE lookupAndDelete #-}-lookupAndDelete :: Monad m => Focus a m (Maybe a)-lookupAndDelete = cases (Nothing, Leave) (\ element -> (Just element, Remove))+lookupAndDelete :: (Monad m) => Focus a m (Maybe a)+lookupAndDelete = cases (Nothing, Leave) (\element -> (Just element, Remove)) -{-|-Reproduces the behaviour of-@Data.Map.<http://hackage.haskell.org/package/containers-0.6.0.1/docs/Data-Map-Lazy.html#v:insert insert>@.--}+-- |+-- Reproduces the behaviour of+-- @Data.Map.<http://hackage.haskell.org/package/containers-0.6.0.1/docs/Data-Map-Lazy.html#v:insert insert>@. {-# INLINE insert #-}-insert :: Monad m => a -> Focus a m ()+insert :: (Monad m) => a -> Focus a m () insert a = unitCases (Set a) (const (Set a)) -{-|-Reproduces the behaviour of-@Data.Map.<http://hackage.haskell.org/package/containers-0.6.0.1/docs/Data-Map-Lazy.html#v:insertWith insertWith>@-with a better name.--}+-- |+-- Reproduces the behaviour of+-- @Data.Map.<http://hackage.haskell.org/package/containers-0.6.0.1/docs/Data-Map-Lazy.html#v:insertWith insertWith>@+-- with a better name. {-# INLINE insertOrMerge #-}-insertOrMerge :: Monad m => (a -> a -> a) -> a -> Focus a m ()-insertOrMerge merge value = unitCases (Set value) (Set . merge value) +insertOrMerge :: (Monad m) => (a -> a -> a) -> a -> Focus a m ()+insertOrMerge merge value = unitCases (Set value) (Set . merge value) -{-|-Reproduces the behaviour of-@Data.Map.<http://hackage.haskell.org/package/containers-0.6.0.1/docs/Data-Map-Lazy.html#v:alter alter>@.--}+-- |+-- Reproduces the behaviour of+-- @Data.Map.<http://hackage.haskell.org/package/containers-0.6.0.1/docs/Data-Map-Lazy.html#v:alter alter>@. {-# INLINE alter #-}-alter :: Monad m => (Maybe a -> Maybe a) -> Focus a m ()+alter :: (Monad m) => (Maybe a -> Maybe a) -> Focus a m () alter fn = unitCases (maybe Leave Set (fn Nothing)) (maybe Remove Set . fn . Just) -{-|-Reproduces the behaviour of-@Data.Map.<http://hackage.haskell.org/package/containers-0.6.0.1/docs/Data-Map-Lazy.html#v:adjust adjust>@.--}+-- |+-- Reproduces the behaviour of+-- @Data.Map.<http://hackage.haskell.org/package/containers-0.6.0.1/docs/Data-Map-Lazy.html#v:adjust adjust>@. {-# INLINE adjust #-}-adjust :: Monad m => (a -> a) -> Focus a m ()+adjust :: (Monad m) => (a -> a) -> Focus a m () adjust fn = unitCases Leave (Set . fn) -{-|-Reproduces the behaviour of-@Data.Map.<http://hackage.haskell.org/package/containers-0.6.0.1/docs/Data-Map-Lazy.html#v:update update>@.--}+-- |+-- Reproduces the behaviour of+-- @Data.Map.<http://hackage.haskell.org/package/containers-0.6.0.1/docs/Data-Map-Lazy.html#v:update update>@. {-# INLINE update #-}-update :: Monad m => (a -> Maybe a) -> Focus a m ()+update :: (Monad m) => (a -> Maybe a) -> Focus a m () update fn = unitCases Leave (maybe Remove Set . fn) -{-|-Same as all of the following expressions:--@\f g -> fmap (fmap f) lookup <* adjust g@-@\f g -> liftStateFn (f &&& g)@-@\f g -> liftStateFn ((,) <$> f <*> g)@--}-accessAndAdjust :: Monad m => (s -> a) -> (s -> s) -> Focus s m (Maybe a)+-- |+-- Same as all of the following expressions:+--+-- @\f g -> fmap (fmap f) lookup <* adjust g@+-- @\f g -> liftStateFn (f &&& g)@+-- @\f g -> liftStateFn ((,) <$> f <*> g)@+accessAndAdjust :: (Monad m) => (s -> a) -> (s -> s) -> Focus s m (Maybe a) accessAndAdjust f g =   liftStateFn (f &&& g) -{-|-Lift a pure state monad.--}-liftState :: Monad m => State s a -> Focus s m (Maybe a)+-- |+-- Lift a pure state monad.+liftState :: (Monad m) => State s a -> Focus s m (Maybe a) liftState (StateT fn) =   liftStateFn (runIdentity . fn) -{-|-Lift a pure state-monad-like function.--}-liftStateFn :: Monad m => (s -> (a, s)) -> Focus s m (Maybe a)+-- |+-- Lift a pure state-monad-like function.+liftStateFn :: (Monad m) => (s -> (a, s)) -> Focus s m (Maybe a) liftStateFn fn =   Focus     (return (Nothing, Leave))     (\s -> case fn s of (a, s) -> return (Just a, Set s))  -- ** Construction utils-------------------------- -{-|-Lift pure functions which handle the cases of presence and absence of the element.--}+-- |+-- Lift pure functions which handle the cases of presence and absence of the element. {-# INLINE cases #-}-cases :: Monad m => (b, Change a) -> (a -> (b, Change a)) -> Focus a m b+cases :: (Monad m) => (b, Change a) -> (a -> (b, Change a)) -> Focus a m b cases sendNone sendSome = Focus (return sendNone) (return . sendSome) -{-|-Lift pure functions which handle the cases of presence and absence of the element and produce no result.--}+-- |+-- Lift pure functions which handle the cases of presence and absence of the element and produce no result. {-# INLINE unitCases #-}-unitCases :: Monad m => Change a -> (a -> Change a) -> Focus a m ()-unitCases sendNone sendSome = cases ((), sendNone) (\ a -> ((), sendSome a))-+unitCases :: (Monad m) => Change a -> (a -> Change a) -> Focus a m ()+unitCases sendNone sendSome = cases ((), sendNone) (\a -> ((), sendSome a))  -- * Monadic functions--------------------------  -- ** Reading functions-------------------------- -{-|-A monadic version of 'lookupWithDefault'.--}-{-# INLINE[1] lookupWithDefaultM #-}-lookupWithDefaultM :: Monad m => m a -> Focus a m a-lookupWithDefaultM aM = casesM (liftM2 (,) aM (return Leave)) (\ a -> return (a, Leave))+-- |+-- A monadic version of 'lookupWithDefault'.+{-# INLINE [1] lookupWithDefaultM #-}+lookupWithDefaultM :: (Monad m) => m a -> Focus a m a+lookupWithDefaultM aM = casesM (liftM2 (,) aM (return Leave)) (\a -> return (a, Leave))  -- ** Modifying functions-------------------------- -{-|-A monadic version of 'insert'.--}+-- |+-- A monadic version of 'insert'. {-# INLINE insertM #-}-insertM :: Monad m => m a -> Focus a m ()+insertM :: (Monad m) => m a -> Focus a m () insertM aM = unitCasesM (fmap Set aM) (const (fmap Set aM)) -{-|-A monadic version of 'insertOrMerge'.--}+-- |+-- A monadic version of 'insertOrMerge'. {-# INLINE insertOrMergeM #-}-insertOrMergeM :: Monad m => (a -> a -> m a) -> m a -> Focus a m ()-insertOrMergeM merge aM = unitCasesM (fmap Set aM) (\ a' -> aM >>= \ a -> fmap Set (merge a a'))+insertOrMergeM :: (Monad m) => (a -> a -> m a) -> m a -> Focus a m ()+insertOrMergeM merge aM = unitCasesM (fmap Set aM) (\a' -> aM >>= \a -> fmap Set (merge a a')) -{-|-A monadic version of 'alter'.--}+-- |+-- A monadic version of 'alter'. {-# INLINE alterM #-}-alterM :: Monad m => (Maybe a -> m (Maybe a)) -> Focus a m ()+alterM :: (Monad m) => (Maybe a -> m (Maybe a)) -> Focus a m () alterM fn = unitCasesM (fmap (maybe Leave Set) (fn Nothing)) (fmap (maybe Remove Set) . fn . Just) -{-|-A monadic version of 'adjust'.--}+-- |+-- A monadic version of 'adjust'. {-# INLINE adjustM #-}-adjustM :: Monad m => (a -> m a) -> Focus a m ()+adjustM :: (Monad m) => (a -> m a) -> Focus a m () adjustM fn = updateM (fmap Just . fn) -{-|-A monadic version of 'update'.--}+-- |+-- A monadic version of 'update'. {-# INLINE updateM #-}-updateM :: Monad m => (a -> m (Maybe a)) -> Focus a m ()+updateM :: (Monad m) => (a -> m (Maybe a)) -> Focus a m () updateM fn = unitCasesM (return Leave) (fmap (maybe Remove Set) . fn)  -- ** Construction utils-------------------------- -{-|-Lift monadic functions which handle the cases of presence and absence of the element.--}+-- |+-- Lift monadic functions which handle the cases of presence and absence of the element. {-# INLINE casesM #-}-casesM :: Monad m => m (b, Change a) -> (a -> m (b, Change a)) -> Focus a m b+casesM :: m (b, Change a) -> (a -> m (b, Change a)) -> Focus a m b casesM sendNone sendSome = Focus sendNone sendSome -{-|-Lift monadic functions which handle the cases of presence and absence of the element and produce no result.--}+-- |+-- Lift monadic functions which handle the cases of presence and absence of the element and produce no result. {-# INLINE unitCasesM #-}-unitCasesM :: Monad m => m (Change a) -> (a -> m (Change a)) -> Focus a m ()-unitCasesM sendNone sendSome = Focus (fmap ((),) sendNone) (\ a -> fmap ((),) (sendSome a))-+unitCasesM :: (Monad m) => m (Change a) -> (a -> m (Change a)) -> Focus a m ()+unitCasesM sendNone sendSome = Focus (fmap ((),) sendNone) (\a -> fmap ((),) (sendSome a))  -- * Composition-------------------------- -{-|-Map the Focus input.--}+-- |+-- Map the Focus input. {-# INLINE mappingInput #-}-mappingInput :: Monad m => (a -> b) -> (b -> a) -> Focus a m x -> Focus b m x-mappingInput aToB bToA (Focus consealA revealA) = Focus consealB revealB where-  consealB = do-    (x, aChange) <- consealA-    return (x, fmap aToB aChange)-  revealB b = do-    (x, aChange) <- revealA (bToA b)-    return (x, fmap aToB aChange)-+mappingInput :: (Monad m) => (a -> b) -> (b -> a) -> Focus a m x -> Focus b m x+mappingInput aToB bToA (Focus consealA revealA) = Focus consealB revealB+  where+    consealB = do+      (x, aChange) <- consealA+      return (x, fmap aToB aChange)+    revealB b = do+      (x, aChange) <- revealA (bToA b)+      return (x, fmap aToB aChange)  -- * Change-inspecting functions-------------------------- -{-|-Extends the output with the input.--}+-- |+-- Extends the output with the input. {-# INLINE extractingInput #-}-extractingInput :: Monad m => Focus a m b -> Focus a m (b, Maybe a)+extractingInput :: (Monad m) => Focus a m b -> Focus a m (b, Maybe a) extractingInput (Focus absent present) =   Focus newAbsent newPresent   where@@ -309,11 +272,10 @@       (b, change) <- present element       return ((b, Just element), change) -{-|-Extends the output with the change performed.--}+-- |+-- Extends the output with the change performed. {-# INLINE extractingChange #-}-extractingChange :: Monad m => Focus a m b -> Focus a m (b, Change a)+extractingChange :: (Monad m) => Focus a m b -> Focus a m (b, Change a) extractingChange (Focus absent present) =   Focus newAbsent newPresent   where@@ -324,11 +286,10 @@       (b, change) <- present element       return ((b, change), change) -{-|-Extends the output with a projection on the change that was performed.--}+-- |+-- Extends the output with a projection on the change that was performed. {-# INLINE projectingChange #-}-projectingChange :: Monad m => (Change a -> c) -> Focus a m b -> Focus a m (b, c)+projectingChange :: (Monad m) => (Change a -> c) -> Focus a m b -> Focus a m (b, c) projectingChange fn (Focus absent present) =   Focus newAbsent newPresent   where@@ -339,35 +300,32 @@       (b, change) <- present element       return ((b, fn change), change) -{-|-Extends the output with a flag,-signaling whether a change, which is not 'Leave', has been introduced.--}+-- |+-- Extends the output with a flag,+-- signaling whether a change, which is not 'Leave', has been introduced. {-# INLINE testingIfModifies #-}-testingIfModifies :: Monad m => Focus a m b -> Focus a m (b, Bool)+testingIfModifies :: (Monad m) => Focus a m b -> Focus a m (b, Bool) testingIfModifies =-  projectingChange $ \ case+  projectingChange $ \case     Leave -> False     _ -> True -{-|-Extends the output with a flag,-signaling whether the 'Remove' change has been introduced.--}+-- |+-- Extends the output with a flag,+-- signaling whether the 'Remove' change has been introduced. {-# INLINE testingIfRemoves #-}-testingIfRemoves :: Monad m => Focus a m b -> Focus a m (b, Bool)+testingIfRemoves :: (Monad m) => Focus a m b -> Focus a m (b, Bool) testingIfRemoves =-  projectingChange $ \ case+  projectingChange $ \case     Remove -> True     _ -> False -{-|-Extends the output with a flag,-signaling whether an item will be inserted.-That is, it didn't exist before and a 'Set' change is introduced.--}+-- |+-- Extends the output with a flag,+-- signaling whether an item will be inserted.+-- That is, it didn't exist before and a 'Set' change is introduced. {-# INLINE testingIfInserts #-}-testingIfInserts :: Monad m => Focus a m b -> Focus a m (b, Bool)+testingIfInserts :: (Monad m) => Focus a m b -> Focus a m (b, Bool) testingIfInserts (Focus absent present) =   Focus newAbsent newPresent   where@@ -376,16 +334,24 @@       let testResult = case change of             Set _ -> True             _ -> False-          in return ((output, testResult), change)+       in return ((output, testResult), change)     newPresent element = do       (output, change) <- present element       return ((output, False), change) -{-|-Extend the output with a flag, signaling how the size will be affected by the change.--}+-- |+-- Extend the output with a flag, signaling how the size will be affected by the change. {-# INLINE testingSizeChange #-}-testingSizeChange :: Monad m => sizeChange {-^ Decreased -} -> sizeChange {-^ Didn't change -} -> sizeChange {-^ Increased -} -> Focus a m b -> Focus a m (b, sizeChange)+testingSizeChange ::+  (Monad m) =>+  -- | Decreased+  sizeChange ->+  -- | Didn't change+  sizeChange ->+  -- | Increased+  sizeChange ->+  Focus a m b ->+  Focus a m (b, sizeChange) testingSizeChange dec none inc (Focus absent present) =   Focus newAbsent newPresent   where@@ -394,31 +360,31 @@       let sizeChange = case change of             Set _ -> inc             _ -> none-          in return ((output, sizeChange), change)+       in return ((output, sizeChange), change)     newPresent element = do       (output, change) <- present element       let sizeChange = case change of             Remove -> dec             _ -> none-          in return ((output, sizeChange), change)-+       in return ((output, sizeChange), change)  -- * STM-------------------------- -{-|-Focus on the contents of a TVar.--}+-- |+-- Focus on the contents of a TVar. {-# INLINE onTVarValue #-} onTVarValue :: Focus a STM b -> Focus (TVar a) STM b-onTVarValue (Focus concealA presentA) = Focus concealTVar presentTVar where-  concealTVar = concealA >>= traverse interpretAChange where-    interpretAChange = \ case-      Leave -> return Leave-      Set !a -> Set <$> newTVar a-      Remove -> return Leave-  presentTVar var = readTVar var >>= presentA >>= traverse interpretAChange where-    interpretAChange = \ case-      Leave -> return Leave-      Set !a -> writeTVar var a $> Leave-      Remove -> return Remove+onTVarValue (Focus concealA presentA) = Focus concealTVar presentTVar+  where+    concealTVar = concealA >>= traverse interpretAChange+      where+        interpretAChange = \case+          Leave -> return Leave+          Set !a -> Set <$> newTVar a+          Remove -> return Leave+    presentTVar var = readTVar var >>= presentA >>= traverse interpretAChange+      where+        interpretAChange = \case+          Leave -> return Leave+          Set !a -> writeTVar var a $> Leave+          Remove -> return Remove
library/Focus/Prelude.hs view
@@ -1,20 +1,24 @@ module Focus.Prelude-(-  module Exports,-)+  ( module Exports,+  ) where --- base-------------------------- import Control.Applicative as Exports import Control.Arrow as Exports import Control.Category as Exports import Control.Concurrent as Exports import Control.Exception as Exports-import Control.Monad as Exports hiding (mapM_, sequence_, forM_, msum, mapM, sequence, forM)-import Control.Monad.IO.Class as Exports+import Control.Monad as Exports hiding (forM, forM_, mapM, mapM_, msum, sequence, sequence_) import Control.Monad.Fix as Exports hiding (fix)+import Control.Monad.IO.Class as Exports import Control.Monad.ST as Exports+import Control.Monad.Trans.Class as Exports+import Control.Monad.Trans.Cont as Exports hiding (callCC, shift)+import Control.Monad.Trans.Except as Exports (Except, ExceptT (ExceptT), catchE, except, mapExcept, mapExceptT, runExcept, runExceptT, throwE, withExcept, withExceptT)+import Control.Monad.Trans.Maybe as Exports+import Control.Monad.Trans.Reader as Exports (Reader, ReaderT (ReaderT), ask, mapReader, mapReaderT, runReader, runReaderT, withReader, withReaderT)+import Control.Monad.Trans.State.Strict as Exports (State, StateT (StateT), evalState, evalStateT, execState, execStateT, mapState, mapStateT, runState, runStateT, withState, withStateT)+import Control.Monad.Trans.Writer.Strict as Exports (Writer, WriterT (..), execWriter, execWriterT, mapWriter, mapWriterT, runWriter) import Data.Bits as Exports import Data.Bool as Exports import Data.Char as Exports@@ -27,17 +31,19 @@ import Data.Foldable as Exports import Data.Function as Exports hiding (id, (.)) import Data.Functor as Exports-import Data.Int as Exports+import Data.Functor.Compose as Exports+import Data.Functor.Identity as Exports import Data.IORef as Exports+import Data.Int as Exports import Data.Ix as Exports-import Data.List as Exports hiding (sortOn, isSubsequenceOf, uncons, concat, foldr, foldl1, maximum, minimum, product, sum, all, and, any, concatMap, elem, foldl, foldr1, notElem, or, find, maximumBy, minimumBy, mapAccumL, mapAccumR, foldl')+import Data.List as Exports hiding (all, and, any, concat, concatMap, elem, find, foldl, foldl', foldl1, foldr, foldr1, isSubsequenceOf, mapAccumL, mapAccumR, maximum, maximumBy, minimum, minimumBy, notElem, or, product, sortOn, sum, uncons) import Data.Maybe as Exports-import Data.Monoid as Exports hiding (Last(..), First(..))+import Data.Monoid as Exports hiding (First (..), Last (..)) import Data.Ord as Exports import Data.Proxy as Exports import Data.Ratio as Exports-import Data.Semigroup as Exports import Data.STRef as Exports+import Data.Semigroup as Exports import Data.String as Exports import Data.Traversable as Exports import Data.Tuple as Exports@@ -48,13 +54,12 @@ import Foreign.ForeignPtr as Exports import Foreign.Ptr as Exports import Foreign.StablePtr as Exports-import Foreign.Storable as Exports hiding (sizeOf, alignment)-import GHC.Conc as Exports hiding (withMVar, threadWaitWriteSTM, threadWaitWrite, threadWaitReadSTM, threadWaitRead)-import GHC.Exts as Exports (lazy, inline, sortWith, groupWith)+import Foreign.Storable as Exports hiding (alignment, sizeOf)+import GHC.Conc as Exports hiding (threadWaitRead, threadWaitReadSTM, threadWaitWrite, threadWaitWriteSTM, withMVar)+import GHC.Exts as Exports (groupWith, inline, lazy, sortWith) import GHC.Generics as Exports (Generic) import GHC.IO.Exception as Exports import Numeric as Exports-import Prelude as Exports hiding (concat, foldr, mapM_, sequence_, foldl1, maximum, minimum, product, sum, all, and, any, concatMap, elem, foldl, foldr1, notElem, or, mapM, sequence, id, (.)) import System.Environment as Exports import System.Exit as Exports import System.IO as Exports@@ -63,21 +68,7 @@ import System.Mem as Exports import System.Mem.StableName as Exports import System.Timeout as Exports-import Text.ParserCombinators.ReadP as Exports (ReadP, ReadS, readP_to_S, readS_to_P)-import Text.ParserCombinators.ReadPrec as Exports (ReadPrec, readPrec_to_P, readP_to_Prec, readPrec_to_S, readS_to_Prec)-import Text.Printf as Exports (printf, hPrintf)-import Text.Read as Exports (Read(..), readMaybe, readEither)+import Text.Printf as Exports (hPrintf, printf)+import Text.Read as Exports (Read (..), readEither, readMaybe) import Unsafe.Coerce as Exports---- transformers---------------------------import Control.Monad.IO.Class as Exports-import Control.Monad.Trans.Class as Exports-import Control.Monad.Trans.Cont as Exports hiding (shift, callCC)-import Control.Monad.Trans.Except as Exports (ExceptT(ExceptT), Except, except, runExcept, runExceptT, mapExcept, mapExceptT, withExcept, withExceptT, throwE, catchE)-import Control.Monad.Trans.Maybe as Exports-import Control.Monad.Trans.Reader as Exports (Reader, ask, runReader, mapReader, withReader, ReaderT(ReaderT), runReaderT, mapReaderT, withReaderT)-import Control.Monad.Trans.State.Strict as Exports (State, runState, evalState, execState, mapState, withState, StateT(StateT), runStateT, evalStateT, execStateT, mapStateT, withStateT)-import Control.Monad.Trans.Writer.Strict as Exports (Writer, runWriter, execWriter, mapWriter, WriterT(..), execWriterT, mapWriterT)-import Data.Functor.Compose as Exports-import Data.Functor.Identity as Exports+import Prelude as Exports hiding (all, and, any, concat, concatMap, elem, foldl, foldl1, foldr, foldr1, id, mapM, mapM_, maximum, minimum, notElem, or, product, sequence, sequence_, sum, (.))
test/Main.hs view
@@ -1,83 +1,69 @@ module Main where -import Prelude hiding (choose)-import Test.QuickCheck.Instances+import qualified Focus import Test.Tasty-import Test.Tasty.Runners import Test.Tasty.HUnit-import Test.Tasty.QuickCheck-import qualified Test.QuickCheck as QuickCheck-import qualified Test.QuickCheck.Property as QuickCheck-import qualified Focus-+import Prelude hiding (choose) +main :: IO () main =   defaultMain $-  testGroup "" $-  [-    testCase "Monadically composed lookup and insert (https://github.com/nikita-volkov/stm-containers/issues/25)" $ let-      Focus.Focus absent present = do-        prev <- Focus.lookup-        Focus.insert "one"-        pure (isJust prev)-      in do-        assertEqual "" (True, Focus.Set "one") $ runIdentity (present "zero")-        assertEqual "" (False, Focus.Set "one") $ runIdentity absent-    ,-    testCase "Applicatively composed lookup and insert" $ let-      Focus.Focus absent present = (isJust <$> Focus.lookup) <* Focus.insert "one"-      in do-        assertEqual "" (True, Focus.Set "one") $ runIdentity (present "zero")-        assertEqual "" (False, Focus.Set "one") $ runIdentity absent-    ,-    testCase "Applicatively composed pure and insert" $ let-      Focus.Focus absent present = pure () <* Focus.insert "one"-      in do-        assertEqual "" ((), Focus.Set "one") (runIdentity (present "zero"))-        assertEqual "" ((), Focus.Set "one") (runIdentity absent)-    ,-    testCase "insert" $ let-      Focus.Focus absent present = Focus.insert "one"-      in do-        assertEqual "" ((), Focus.Set "one") (runIdentity (present "zero"))-        assertEqual "" ((), Focus.Set "one") (runIdentity absent)-    ,-    testCase "alter" $ let-      f :: Maybe String -> Maybe String-      f = const Nothing-      Focus.Focus absent present = Focus.alter f-      in do-        assertEqual "" ((), Focus.Remove) (runIdentity (present "zero"))-        assertEqual "" ((), Focus.Leave) (runIdentity absent)-    ,-    testCase "update" $ let-      f :: String -> Maybe String-      f = const Nothing-      Focus.Focus absent present = Focus.update f-      in do-        assertEqual "" ((), Focus.Remove) (runIdentity (present "zero"))-        assertEqual "" ((), Focus.Leave) (runIdentity absent)-    ,-    testCase "updateM" $ let-      f :: String -> Identity (Maybe String)-      f = const (pure Nothing)-      Focus.Focus absent present = Focus.updateM f-      in do-        assertEqual "" ((), Focus.Remove) (runIdentity (present "zero"))-        assertEqual "" ((), Focus.Leave) (runIdentity absent)-    ,-    testCase "delete" $ let-      Focus.Focus absent present = Focus.delete-      in do-        assertEqual "" ((), Focus.Remove) (runIdentity (present "zero"))-        assertEqual "" ((), Focus.Leave @()) (runIdentity absent)-    ,-    testCase "Monadically composed lookup and delete (https://github.com/nikita-volkov/focus/issues/7)" $ let-      Focus.Focus absent present = do-        a <- Focus.lookup-        Focus.delete-        pure a-      in do-        assertEqual "" (Just (), Focus.Remove) (runIdentity (present ()))-        assertEqual "" (Nothing @(), Focus.Leave) (runIdentity absent)-  ]+    testGroup "" $+      [ testCase "Monadically composed lookup and insert (https://github.com/nikita-volkov/stm-containers/issues/25)" $+          let Focus.Focus absent present = do+                prev <- Focus.lookup+                Focus.insert "one"+                pure (isJust prev)+           in do+                assertEqual "" (True, Focus.Set "one") $ runIdentity (present "zero")+                assertEqual "" (False, Focus.Set "one") $ runIdentity absent,+        testCase "Applicatively composed lookup and insert" $+          let Focus.Focus absent present = (isJust <$> Focus.lookup) <* Focus.insert "one"+           in do+                assertEqual "" (True, Focus.Set "one") $ runIdentity (present "zero")+                assertEqual "" (False, Focus.Set "one") $ runIdentity absent,+        testCase "Applicatively composed pure and insert" $+          let Focus.Focus absent present = pure () <* Focus.insert "one"+           in do+                assertEqual "" ((), Focus.Set "one") (runIdentity (present "zero"))+                assertEqual "" ((), Focus.Set "one") (runIdentity absent),+        testCase "insert" $+          let Focus.Focus absent present = Focus.insert "one"+           in do+                assertEqual "" ((), Focus.Set "one") (runIdentity (present "zero"))+                assertEqual "" ((), Focus.Set "one") (runIdentity absent),+        testCase "alter" $+          let f :: Maybe String -> Maybe String+              f = const Nothing+              Focus.Focus absent present = Focus.alter f+           in do+                assertEqual "" ((), Focus.Remove) (runIdentity (present "zero"))+                assertEqual "" ((), Focus.Leave) (runIdentity absent),+        testCase "update" $+          let f :: String -> Maybe String+              f = const Nothing+              Focus.Focus absent present = Focus.update f+           in do+                assertEqual "" ((), Focus.Remove) (runIdentity (present "zero"))+                assertEqual "" ((), Focus.Leave) (runIdentity absent),+        testCase "updateM" $+          let f :: String -> Identity (Maybe String)+              f = const (pure Nothing)+              Focus.Focus absent present = Focus.updateM f+           in do+                assertEqual "" ((), Focus.Remove) (runIdentity (present "zero"))+                assertEqual "" ((), Focus.Leave) (runIdentity absent),+        testCase "delete" $+          let Focus.Focus absent present = Focus.delete+           in do+                assertEqual "" ((), Focus.Remove) (runIdentity (present "zero"))+                assertEqual "" ((), Focus.Leave @()) (runIdentity absent),+        testCase "Monadically composed lookup and delete (https://github.com/nikita-volkov/focus/issues/7)" $+          let Focus.Focus absent present = do+                a <- Focus.lookup+                Focus.delete+                pure a+           in do+                assertEqual "" (Just (), Focus.Remove) (runIdentity (present ()))+                assertEqual "" (Nothing @(), Focus.Leave) (runIdentity absent)+      ]