packages feed

incremental-computing 0.0.0.0 → 0.0.1.0

raw patch · 13 files changed

+754/−376 lines, 13 filesdep +deepseqdep ~QuickCheckdep ~dlistdep ~incremental-computingPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: deepseq

Dependency ranges changed: QuickCheck, dlist, incremental-computing, order-maintenance, transformers

API changes (from Hackage documentation)

- Data.Incremental: instance Category Trans
- Data.Incremental: instance Change (PrimitiveChange a)
- Data.Incremental: instance Changeable Bool
- Data.Incremental: instance Changeable Int
- Data.Incremental: instance Functor PrimitiveChange
- Data.Incremental: instance Monoid (PrimitiveChange a)
- Data.Incremental: instance Read a => Read (PrimitiveChange a)
- Data.Incremental: instance Show a => Show (PrimitiveChange a)
- Data.Incremental: instance Typeable Cell
- Data.Incremental: instance Typeable Change
- Data.Incremental: instance Typeable Changeable
- Data.Incremental: instance Typeable Trans
- Data.Incremental.Sequence: instance Change p => Change (OrderChange p)
- Data.Incremental.Sequence: instance Changeable a => Change (AtomicChange a)
- Data.Incremental.Sequence: instance Changeable a => Changeable (OrderValue a)
- Data.Incremental.Sequence: instance Changeable a => Changeable (Seq a)
- Data.Incremental.Sequence: instance Eq (OrderValue a)
- Data.Incremental.Sequence: instance Measured ConcatStateMeasure ConcatStateElement
- Data.Incremental.Sequence: instance Monoid ConcatStateMeasure
- Data.Incremental.Sequence: instance Monoid p => Monoid (OrderChange p)
- Data.Incremental.Sequence: instance Ord (OrderValue a)
- Data.Incremental.Sequence: instance Typeable AtomicChange
- Data.Incremental.Sequence: instance Typeable ConcatStateElement
- Data.Incremental.Sequence: instance Typeable ConcatStateMeasure
- Data.Incremental.Sequence: instance Typeable OrderValue
- Data.Incremental.Tuple: instance (Changeable a, Changeable b) => Change (AtomicChange a b)
- Data.Incremental.Tuple: instance (Changeable a, Changeable b) => Changeable (a, b)
- Data.Incremental.Tuple: instance Typeable AtomicChange
- Data.MultiChange: instance Change p => Change (MultiChange p)
- Data.MultiChange: instance Foldable MultiChange
- Data.MultiChange: instance Monoid (MultiChange p)
- Data.MultiChange: instance Read p => Read (MultiChange p)
- Data.MultiChange: instance Show p => Show (MultiChange p)
+ Data.Incremental: instance Control.Category.Category Data.Incremental.Trans
+ Data.Incremental: instance Data.Incremental.Change (Data.Incremental.PrimitiveChange a)
+ Data.Incremental: instance Data.Incremental.Changeable GHC.Types.Bool
+ Data.Incremental: instance Data.Incremental.Changeable GHC.Types.Int
+ Data.Incremental: instance GHC.Base.Functor Data.Incremental.PrimitiveChange
+ Data.Incremental: instance GHC.Base.Monoid (Data.Incremental.PrimitiveChange a)
+ Data.Incremental: instance GHC.Read.Read a => GHC.Read.Read (Data.Incremental.PrimitiveChange a)
+ Data.Incremental: instance GHC.Show.Show a => GHC.Show.Show (Data.Incremental.PrimitiveChange a)
+ Data.Incremental: stateTrans' :: (Value p -> (Value q, s)) -> (p -> s -> (q, s)) -> Trans p q
+ Data.Incremental: type DefaultChange a = PrimitiveChange a;
+ Data.Incremental: type family DefaultChange a :: *;
+ Data.Incremental: }
+ Data.Incremental.Sequence: instance Data.FingerTree.Measured Data.Incremental.Sequence.ConcatStateMeasure Data.Incremental.Sequence.ConcatStateElement
+ Data.Incremental.Sequence: instance Data.Incremental.Change p => Data.Incremental.Change (Data.Incremental.Sequence.OrderChange p)
+ Data.Incremental.Sequence: instance Data.Incremental.Changeable a => Data.Incremental.Change (Data.Incremental.Sequence.AtomicChange a)
+ Data.Incremental.Sequence: instance Data.Incremental.Changeable a => Data.Incremental.Changeable (Data.Incremental.Sequence.OrderValue a)
+ Data.Incremental.Sequence: instance Data.Incremental.Changeable a => Data.Incremental.Changeable (Data.Sequence.Seq a)
+ Data.Incremental.Sequence: instance GHC.Base.Monoid Data.Incremental.Sequence.ConcatStateMeasure
+ Data.Incremental.Sequence: instance GHC.Base.Monoid p => GHC.Base.Monoid (Data.Incremental.Sequence.OrderChange p)
+ Data.Incremental.Sequence: instance GHC.Classes.Eq (Data.Incremental.Sequence.OrderValue a)
+ Data.Incremental.Sequence: instance GHC.Classes.Eq val => GHC.Classes.Eq (Data.Incremental.Sequence.Tagged o val)
+ Data.Incremental.Sequence: instance GHC.Classes.Ord (Data.Incremental.Sequence.OrderValue a)
+ Data.Incremental.Sequence: instance GHC.Classes.Ord val => GHC.Classes.Ord (Data.Incremental.Sequence.Tagged o val)
+ Data.Incremental.Tuple: instance (Data.Incremental.Changeable a, Data.Incremental.Changeable b) => Data.Incremental.Change (Data.Incremental.Tuple.AtomicChange a b)
+ Data.Incremental.Tuple: instance (Data.Incremental.Changeable a, Data.Incremental.Changeable b) => Data.Incremental.Changeable (a, b)
+ Data.MultiChange: instance Data.Foldable.Foldable Data.MultiChange.MultiChange
+ Data.MultiChange: instance Data.Incremental.Change p => Data.Incremental.Change (Data.MultiChange.MultiChange p)
+ Data.MultiChange: instance GHC.Base.Monoid (Data.MultiChange.MultiChange p)
+ Data.MultiChange: instance GHC.Read.Read p => GHC.Read.Read (Data.MultiChange.MultiChange p)
+ Data.MultiChange: instance GHC.Show.Show p => GHC.Show.Show (Data.MultiChange.MultiChange p)
- Data.Incremental: class Change p where type family Value p :: *
+ Data.Incremental: class Change p where type Value p :: * where {
- Data.Incremental: class (Monoid (DefaultChange a), Change (DefaultChange a), Value (DefaultChange a) ~ a) => Changeable a where type family DefaultChange a :: * type instance DefaultChange a = PrimitiveChange a
+ Data.Incremental: class (Monoid (DefaultChange a), Change (DefaultChange a), Value (DefaultChange a) ~ a) => Changeable a where type DefaultChange a :: * type DefaultChange a = PrimitiveChange a where {
- Data.Incremental.Sequence: Insert :: !Int -> (Seq a) -> AtomicChange a
+ Data.Incremental.Sequence: Insert :: !Int -> !(Seq a) -> AtomicChange a

Files

+ dist/build/sequence-testsStub/sequence-testsStub-tmp/sequence-testsStub.hs view
@@ -0,0 +1,5 @@+module Main ( main ) where+import Distribution.Simple.Test.LibV09 ( stubMain )+import TestSuite.Sequence ( tests )+main :: IO ()+main = stubMain tests
incremental-computing.cabal view
@@ -1,5 +1,5 @@ Name:          incremental-computing-Version:       0.0.0.0+Version:       0.0.1.0 Cabal-Version: >= 1.16 Build-Type:    Simple License:       BSD3@@ -9,11 +9,11 @@ Maintainer:    wolfgang@cs.ioc.ee Stability:     provisional Homepage:      http://darcs.wolfgang.jeltsch.info/haskell/incremental-computing-Package-URL:   http://hackage.haskell.org/packages/archive/incremental-computing/0.0.0.0/incremental-computing-0.0.0.0.tar.gz+Package-URL:   http://hackage.haskell.org/packages/archive/incremental-computing/0.0.1.0/incremental-computing-0.0.1.0.tar.gz Synopsis:      Incremental computing Description:   This package is about incremental computing. Category:      Data-Tested-With:   GHC == 7.8.3+Tested-With:   GHC == 8.0.1  Source-Repository head @@ -24,16 +24,16 @@      Type:     darcs     Location: http://darcs.wolfgang.jeltsch.info/haskell/incremental-computing/main-    Tag:      incremental-computing-0.0.0.0+    Tag:      incremental-computing-0.0.1.0  Library      Build-Depends: base              >= 3.0 && < 5,                    containers        >= 0.1 && < 0.6,-                   dlist             >= 0.7 && < 0.8,+                   dlist             >= 0.7 && < 0.9,                    fingertree        >= 0.1 && < 0.2,-                   order-maintenance >= 0.0 && < 0.1,-                   transformers      >= 0.3 && < 0.5+                   order-maintenance >= 0.1 && < 0.2,+                   transformers      >= 0.3 && < 0.6      Default-Language: Haskell2010 @@ -44,10 +44,6 @@                         TypeFamilies                         TypeOperators -    if impl(ghc >= 7.8) {-        Default-Extensions: AutoDeriveTypeable-    }-     Exposed-Modules: Data.Incremental                      Data.Incremental.Sequence                      Data.Incremental.Tuple@@ -59,12 +55,12 @@      Type: detailed-0.9 -    Build-Depends: base                  >= 3.0  && < 5,-                   Cabal                 >= 1.16 && < 2,-                   cabal-test-quickcheck >= 0.1  && < 0.2,-                   containers            >= 0.1  && < 0.6,-                   QuickCheck            >= 2.6  && < 3,-                   incremental-computing == 0.0.0.0+    Build-Depends: base                  >= 3.0   && < 5,+                   Cabal                 >= 1.16  && < 2,+                   cabal-test-quickcheck >= 0.1   && < 0.2,+                   containers            >= 0.1   && < 0.6,+                   QuickCheck            >= 2.8.2 && < 3,+                   incremental-computing == 0.0.1.0      Default-Language: Haskell2010 @@ -79,5 +75,31 @@     Test-Module: TestSuite.Sequence      Other-Modules: TestSuite+                   Utilities -    HS-Source-Dirs: src/test-suites+    HS-Source-Dirs: src/tools++Benchmark benchmark++    Type: exitcode-stdio-1.0++    Build-Depends: base                  >= 3.0   && < 5,+                   containers            >= 0.1   && < 0.6,+                   deepseq               >= 1.3   && < 1.5,+                   QuickCheck            >= 2.8.2 && < 3,+                   incremental-computing == 0.0.1.0++    Default-Language: Haskell2010++    Default-Extensions: FlexibleContexts+                        TypeFamilies+                        TypeOperators++    Other-Extensions: UndecidableInstances++    Main-Is: Benchmark/Sequence.hs++    Other-Modules: Benchmark+                   Utilities++    HS-Source-Dirs: src/tools
src/library/Data/Incremental.hs view
@@ -14,6 +14,7 @@      simpleTrans,     stateTrans,+    stateTrans',     stTrans,     trans, @@ -131,6 +132,30 @@             return change'     return (val', stProp)) +{-FIXME:+    Say in the documentation that stateTrans' is state-strict in the sense that+    reduction of the initial target value and any target change will result in+    reduction of the state. Point out that reduction is only to WHNF, so that+    the initializer and propagator have to make sure that WHNF reduction+    triggers more reduction (for example, by using a data type with strict+    fields) if this is desired.+-}+stateTrans' :: (Value p -> (Value q, s)) -> (p -> s -> (q, s)) -> Trans p q+stateTrans' init prop = stateTrans init' prop' where++    init' val = (initState `seq` val', initState) where++        (val', initState) = init val++    prop' change oldState = (newState `seq` change', newState) where++        (change', newState) = prop change oldState++{-FIXME:+    Say in the documentation that it is the resposibility of the user of stTrans+    to make sure that reductions of the initial target and target changes+    trigger evaluation of any parts of the state for which this is desired.+-} stTrans :: (forall s . TransProc (ST s) p q) -> Trans p q stTrans transProc = trans (\ cont -> runST (cont transProc)) @@ -151,14 +176,18 @@     lazy. If it is strict, the constructed transformation trans will (probably)     have the following properties: -      • Reducing any expression runTrans trans valAndChanges to WHNF results in-        the initialization being run and the constructed propagator being run on-        all the changes.+      • Reducing any expression runTrans trans src to WHNF results in the+        initialization being run and the constructed propagator being run on all+        the changes.        • The expression toSTProc trans is a processor that always yields ⊥ as the         output value and constructs propagators that always yield ⊥ as the         output change. -}+{-FIXME:+    Say in the documentation that what holds for stTrans regarding state+    strictness also holds for trans.+-} trans :: (forall r . (forall m . Monad m => TransProc m p q -> m r) -> r)       -> Trans p q trans cpsProcAndRun = errorIfStrictMonad `seq` Trans conv where@@ -169,8 +198,7 @@     strictMonadError = error "Data.Incremental: \                              \Transformation processor uses strict monad" -    conv valAndChanges = cpsProcAndRun $-                         \ transProc -> monadicConv transProc valAndChanges+    conv src = cpsProcAndRun $ \ transProc -> monadicConv transProc src      monadicConv transProc ~(val, changes) = do         ~(val', prop) <- transProc val@@ -317,6 +345,21 @@     cellRef' <- newSTRef undefined     writeSTRef cellRef (Cell val cellRef')     writeSTRef chan cellRef'+{-FIXME:+    We had the following implementation of writeChannel temporarily, which was+    inspired by the implementation of Control.Concurrent.Chan.writeChan:++        writeChannel :: Channel s a -> a -> ST s ()+        writeChannel chan val = do+            cellRef' <- newSTRef undefined+            mask_ $ do+                cellRef <- readSTRef chan+                writeSTRef cellRef (Cell val cellRef')+                writeSTRef chan cellRef'++    However, this implementation does not work, since mask_ is an IO action, not+    an ST action. Do we need to mask asynchronous events?+-}  {-FIXME:     Is there already an implementation of ST channels?
src/library/Data/Incremental/Sequence.hs view
@@ -41,6 +41,14 @@  ) where +{-FIXME:+    Starting with GHC 7.10, we probably do not need to hide Prelude.foldl and+    import Data.Foldable (at least Data.Foldable.foldl' and+    Data.Foldable.toList, because the “Burning Bridges Proposal” has been+    implemented (meaning that certain Prelude functions are now the more general+    versions from Data.Foldable and Data.Traversable).+-}+ -- Prelude  import Prelude hiding (@@ -66,7 +74,7 @@ -- Data  import           Data.Monoid-import           Data.Foldable (foldl, asum, toList)+import           Data.Foldable (foldl', asum, toList) import           Data.Traversable (traverse) import           Data.FingerTree (FingerTree, Measured (measure)) import qualified Data.FingerTree as FingerTree@@ -75,6 +83,7 @@ import           Data.Set (Set) import qualified Data.Set as Set import           Data.STRef.Lazy+import           Data.Order import           Data.MultiChange (MultiChange) import qualified Data.MultiChange as MultiChange import           Data.Incremental@@ -94,7 +103,30 @@         refers to the situation before applying this change gets the         corresponding identifier that starts with “old”. -}+{-NOTE:+    State-strictness policy: +      • Reduction of the initial target value causes reduction of the state.++      • In the case of a sequence source, reduction of the part of a target+        change that is generated from an atomic change causes reduction of the+        state that is current just after this atomic change.++      • In the case of a non-sequence source, reduction of a target change+        causes reduction of the state.++      • State data structures are mostly strict, so that reduction of state+        causes evaluation of most of the state.++      • Only in the case of gate, the state data structure is not fully strict.+        Here, the state contains the current source value lazily. Maybe this+        should be changed.++      • In the case of map, state of the element transformation is only reduced+        if the corresponding initial target element or target element change+        (which is embedded in a ChangeAt change) is reduced.+-}+ -- * Changes  instance Changeable a => Changeable (Seq a) where@@ -115,12 +147,18 @@  -- * Atomic changes -data AtomicChange a = Insert !Int (Seq a)+data AtomicChange a = Insert !Int !(Seq a)                     | Delete !Int !Int                     | Shift !Int !Int !Int                     | ChangeAt !Int (DefaultChange a)-{-FIXME:-    Are these strictness annotations sensible? Should the sequence be strict?+{-NOTE:+    Insert is strict in the sequence, since it should be strict in the length of+    the sequence, as Delete and Shift are also strict in the length of the+    sequence length. Actually, reducing a sequence to WHNF evaluates everything+    except the elements, which amounts to evaluating its length.++    ChangeAt is not strict in the element change, since MultiChange is also not+    strict in its elements. -}  {-NOTE:@@ -197,9 +235,6 @@          len' = (len `max` 0) `min` (totalLen - ix') -noChange :: Changeable a => AtomicChange a-noChange = ChangeAt (-1) mempty- changeLength :: AtomicChange a -> Int -> Int changeLength (Insert _ seq) totalLength = totalLength + Seq.length seq changeLength (Delete _ len) totalLength = totalLength - len@@ -238,7 +273,7 @@ null = fromFunction (== 0) . length  length :: Changeable a => Seq a ->> Int-length = MultiChange.composeMap $ stateTrans init prop where+length = MultiChange.composeMap $ stateTrans' init prop where      init seq = (len, len) where @@ -253,36 +288,40 @@ -- ** Mapping  map :: (Changeable a, Changeable b) => (a ->> b) -> Seq a ->> Seq b-map trans = MultiChange.map $ stTrans (\ seq -> do+map trans = MultiChange.bind $ stTrans (\ seq -> do     let elemProc = toSTProc trans     let seqInit seq = do             procOutputs <- traverse elemProc seq             return (fmap fst procOutputs, fmap snd procOutputs)-    (seq', elemProps) <- seqInit seq-    elemPropsRef <- newSTRef elemProps-    let prop (Insert ix seq) = do+    (seq', initElemProps) <- seqInit seq+    elemPropsRef <- newSTRef initElemProps+    let propCore (Insert ix seq) = do             (seq', elemProps) <- seqInit seq             modifySTRef elemPropsRef (applyInsert ix elemProps)-            return (Insert ix seq')-        prop (Delete ix len) = do+            return (insert ix seq')+        propCore (Delete ix len) = do             modifySTRef elemPropsRef (applyDelete ix len)-            return (Delete ix len)-        prop (Shift src len tgt) = do+            return (delete ix len)+        propCore (Shift src len tgt) = do             modifySTRef elemPropsRef (applyShift src len tgt)-            return (Shift src len tgt)-        prop (ChangeAt ix change) = do+            return (shift src len tgt)+        propCore (ChangeAt ix change) = do             elemProps <- readSTRef elemPropsRef             if indexInBounds (Seq.length elemProps) ix                 then do                     let elemProp = Seq.index elemProps ix                     change' <- elemProp change-                    return (ChangeAt ix change')-                else return noChange-    return (seq', prop))+                    return (changeAt ix change')+                else return mempty+    let prop change = do+            change' <- propCore change+            newElemProps <- readSTRef elemPropsRef+            return (newElemProps `Prelude.seq` change')+    return (initElemProps `Prelude.seq` seq', prop))  map' :: (Changeable a, DefaultChange a ~ PrimitiveChange a,-        Changeable b, DefaultChange b ~ PrimitiveChange b) =>-       (a -> b) -> Seq a ->> Seq b+         Changeable b, DefaultChange b ~ PrimitiveChange b) =>+        (a -> b) -> Seq a ->> Seq b map' fun = MultiChange.map $ simpleTrans (fmap fun) prop where      prop (Insert ix seq)      = Insert ix (fmap fun seq)@@ -298,8 +337,8 @@ newtype ConcatStateElement = ConcatStateElement Int  data ConcatStateMeasure = ConcatStateMeasure {-                              sourceLength :: Int,-                              targetLength :: Int+                              sourceLength :: !Int,+                              targetLength :: !Int                           }  instance Monoid ConcatStateMeasure where@@ -313,7 +352,7 @@  instance Measured ConcatStateMeasure ConcatStateElement where -    measure (ConcatStateElement elLen) = ConcatStateMeasure 1 elLen+    measure (ConcatStateElement elemLen) = ConcatStateMeasure 1 elemLen  type ConcatState = FingerTree ConcatStateMeasure ConcatStateElement @@ -322,8 +361,10 @@                    toList              .                    fmap (ConcatStateElement . Seq.length) +data ChangeAndLength a = ChangeAndLength (DefaultChange (Seq a)) !Int+ concat :: Changeable a => Seq (Seq a) ->> Seq a-concat = MultiChange.bind $ stateTrans init prop where+concat = MultiChange.bind $ stateTrans' init prop where      init seq = (seqConcat seq, seqToConcatState seq) @@ -367,43 +408,33 @@          (ConcatStateElement elemLen FingerTree.:< rear) = FingerTree.viewl rest -        (change', elemLen') = foldl next (mempty, elemLen) change where+        ChangeAndLength change' elemLen' = foldl' next init change where -            next (curChange, curElemLen) atomic = (curChange', curElemLen') where+            init = ChangeAndLength mempty elemLen +            next (ChangeAndLength curChange curElemLen) atomic = result where++                result = ChangeAndLength curChange' curElemLen'+                 normAtomic = normalizeAtomicChange curElemLen atomic                  shiftedNormAtomic = case normAtomic of                     Insert elemIx seq-                        -> Insert (ix' + elemIx) seq+                        -> insert (ix' + elemIx) seq                     Delete elemIx curElemLen-                        -> Delete (ix' + elemIx) curElemLen+                        -> delete (ix' + elemIx) curElemLen                     Shift elemSrc curElemLen elemTgt-                        -> Shift (ix' + elemSrc) curElemLen (ix' + elemTgt)+                        -> shift (ix' + elemSrc) curElemLen (ix' + elemTgt)                     ChangeAt elemIx change                         -> if indexInBounds curElemLen elemIx-                               then ChangeAt (ix' + elemIx) change-                               else noChange+                               then changeAt (ix' + elemIx) change+                               else mempty -                curChange' = MultiChange.singleton shiftedNormAtomic `mappend`-                             curChange+                curChange' = shiftedNormAtomic `mappend` curChange                  curElemLen' = changeLength normAtomic curElemLen-        -- NOTE: Strictness is not perfect.-        -- FIXME: One line too wide.          state' = front <> (ConcatStateElement elemLen' FingerTree.<| rear)-        {-NOTE:-            This is a bit fishy. Even if the inner change is illegal, we get a-            non-⊥ state. So the state is not always a property of the original-            value. If the original value is ⊥, the state might not be ⊥.-            However, this should not result in violation of the main property-            that changing and then transforming is the same as transforming and-            then changing with the propagated change. We would propagate to-            non-⊥ changes in the future, but applying these to ⊥ yields ⊥. The-            latter might not always be the case, but it is the case for-            sequences.-        -}      splitAndTranslate :: Int -> ConcatState -> (Int, ConcatState, ConcatState)     splitAndTranslate ix state = (ix', front, rear) where@@ -422,7 +453,7 @@ gate :: Changeable a => (a ->> Bool) -> a ->> Seq a gate prd = stTrans (\ val -> do     valRef <- newSTRef val-    ~(accepted, prop) <- toSTProc prd val+    (accepted, prop) <- toSTProc prd val     acceptedRef <- newSTRef accepted     let prop' change = do             oldVal <- readSTRef valRef@@ -449,7 +480,7 @@  gate' :: (Changeable a, DefaultChange a ~ PrimitiveChange a) =>          (a -> Bool) -> a ->> Seq a-gate' prd = stateTrans init prop where+gate' prd = stateTrans' init prop where      init val = (emptyOrSingleton accepted val, accepted) where @@ -484,7 +515,7 @@ -- ** Reversal  reverse :: Changeable a => Seq a ->> Seq a-reverse = MultiChange.map $ stateTrans init prop where+reverse = MultiChange.map $ stateTrans' init prop where      init seq = (Seq.reverse seq, Seq.length seq) @@ -510,10 +541,12 @@  -- ** Sorting +data Tagged o val = Tagged !val !(Element o) deriving (Eq, Ord)+ sort :: (Ord a, Changeable a) => Seq a ->> Seq a sort = MultiChange.bind $ orderSTTrans (\ seq -> do     let seq' = Seq.sort seq-    initTaggedSeq <- traverse (\ elem -> fmap ((,) elem) newMaximum) seq+    initTaggedSeq <- traverse (\ elem -> fmap (Tagged elem) newMaximum) seq     let initTaggedSet = Set.fromList (toList initTaggedSeq)     taggedSeqRef <- lift $ newSTRef initTaggedSeq     taggedSetRef <- lift $ newSTRef initTaggedSet@@ -521,22 +554,23 @@             taggedSeq <- lift $ readSTRef taggedSeqRef             let (front, rest) = Seq.splitAt ix taggedSeq             tag <- case Seq.viewl rest of-                       Seq.EmptyL                -> newMaximum-                       (_, neighborTag) Seq.:< _ -> newBefore neighborTag-            lift $ writeSTRef taggedSeqRef (front >< (elem, tag) Seq.<| rest)+                       Seq.EmptyL                    -> newMaximum+                       Tagged _ neighborTag Seq.:< _ -> newBefore neighborTag+            lift $ writeSTRef taggedSeqRef+                              (front >< Tagged elem tag Seq.<| rest)             oldTaggedSet <- lift $ readSTRef taggedSetRef-            let newTaggedSet = Set.insert (elem, tag) oldTaggedSet+            let newTaggedSet = Set.insert (Tagged elem tag) oldTaggedSet             lift $ writeSTRef taggedSetRef newTaggedSet-            return (Set.findIndex (elem, tag) newTaggedSet)+            return (Set.findIndex (Tagged elem tag) newTaggedSet)     let performDelete ix = do             taggedSeq <- lift $ readSTRef taggedSeqRef             let (front, rest) = Seq.splitAt ix taggedSeq-            let (elem, tag) Seq.:< rear = Seq.viewl rest+            let Tagged elem tag Seq.:< rear = Seq.viewl rest             lift $ writeSTRef taggedSeqRef (front >< rear)             taggedSet <- lift $ readSTRef taggedSetRef             lift $ writeSTRef taggedSetRef-                              (Set.delete (elem, tag) taggedSet)-            return (Set.findIndex (elem, tag) taggedSet)+                              (Set.delete (Tagged elem tag) taggedSet)+            return (Set.findIndex (Tagged elem tag) taggedSet)     let elemInsert ix elem = do             ix' <- performInsert ix elem             return (Insert ix' (Seq.singleton elem))@@ -545,17 +579,17 @@             return (Delete ix' 1)     let elemShift src tgt = do             taggedSeq <- lift $ readSTRef taggedSeqRef-            let elem = fst (Seq.index taggedSeq src)+            let Tagged elem _ = Seq.index taggedSeq src             src' <- performDelete src             tgt' <- performInsert tgt elem             return (Shift src' 1 tgt')-    let propNorm (Insert ix seq) = do+    let propCore (Insert ix seq) = do             changes' <- traverse (elemInsert ix) (Prelude.reverse (toList seq))             return (MultiChange.fromList changes')-        propNorm (Delete ix len) = do+        propCore (Delete ix len) = do             changes' <- traverse elemDelete (replicate len ix)             return (MultiChange.fromList changes')-        propNorm (Shift src len tgt) = (case compare src tgt of+        propCore (Shift src len tgt) = (case compare src tgt of             LT -> genShifts (Prelude.reverse [0 .. len - 1])             GT -> genShifts [0 .. len - 1]             EQ -> return mempty) where@@ -566,20 +600,26 @@              genShift offset = elemShift (src + offset) (tgt + offset) -        propNorm (ChangeAt ix change) = do+        propCore (ChangeAt ix change) = do             taggedSeq <- lift $ readSTRef taggedSeqRef             if indexInBounds (Seq.length taggedSeq) ix                 then do-                    let (oldElem, _) = Seq.index taggedSeq ix+                    let Tagged oldElem _ = Seq.index taggedSeq ix                     let newElem = change $$ oldElem                     src' <- performDelete ix                     tgt' <- performInsert ix newElem                     return (shift src' 1 tgt' `mappend` changeAt src' change)                 else return mempty     let prop change = do-            taggedSeq <- lift $ readSTRef taggedSeqRef-            propNorm (normalizeAtomicChange (Seq.length taggedSeq) change)-    return (seq', prop))+            oldTaggedSeq <- lift $ readSTRef taggedSeqRef+            change' <- propCore $+                       normalizeAtomicChange (Seq.length oldTaggedSeq) change+            newTaggedSeq <- lift $ readSTRef taggedSeqRef+            newTaggedSet <- lift $ readSTRef taggedSetRef+            return $ newTaggedSeq `Prelude.seq`+                     newTaggedSet `Prelude.seq`+                     change'+    return (initTaggedSet `Prelude.seq` seq', prop))  orderSTTrans :: (forall o s . TransProc (OrderT o (ST s)) p q) -> Trans p q orderSTTrans transProc = trans (\ cont -> runST (evalOrderT (cont transProc)))
src/library/Data/Incremental/Tuple.hs view
@@ -73,6 +73,11 @@             return (first change1 `mappend` second change2)     return ((val1, val2), prop)) +{-FIXME:+    Could we have a strictness issue, since with fst, the changes under Second,+    and with snd, the changes under First are not triggered?+-}+ fst :: (Changeable a, Changeable b) => (a, b) ->> a fst = MultiChange.composeMap $ simpleTrans Prelude.fst prop where 
src/library/Data/MultiChange.hs view
@@ -70,12 +70,24 @@     foldMap fun (MultiChange (Dual dList)) = foldMap fun dList      foldr next init (MultiChange (Dual dList)) = Foldable.foldr next init dList+    {-FIXME:+        Starting with GHC 7.10, Foldable.foldr can probably be written just+        foldr, because the “Burning Bridges Proposal” has been implemented+        (meaning that Prelude functions like foldr are now the more general+        versions from Data.Foldable and Data.Traversable).+    -}  instance Change p => Change (MultiChange p) where      type Value (MultiChange p) = Value p      change $$ val = List.foldl' (flip ($$)) val (toList change)+    {-FIXME:+        Starting with GHC 7.10, List.foldl' can probably be written just+        foldl', because the “Burning Bridges Proposal” has been implemented+        (meaning that Data.List functions like foldl' are now the more general+        versions from Data.Foldable and Data.Traversable).+    -}  -- * Construction 
− src/test-suites/TestSuite.hs
@@ -1,210 +0,0 @@-{-# LANGUAGE UndecidableInstances #-}-module TestSuite (--    -- * Changes--    AtomicAChange (DoubleAndAdd),-    AtomicBChange (TripleAndAdd),--    -- * Test functions and transformations--    testTrans,-    testFun,-    testPrdTrans,-    testPrdFun,-    testCompare,--    -- * Test pattern--    transTest--) where---- Prelude--import Prelude hiding (id, (.))---- Control--import Control.Category-import Control.Applicative---- Data--import           Data.Foldable (toList)-import           Data.MultiChange (MultiChange)-import qualified Data.MultiChange               as MultiChange-import           Data.Sequence (Seq)-import qualified Data.Sequence                  as Seq-import           Data.Incremental-import qualified Data.Incremental.Tuple         as Tuple-import qualified Data.Incremental.Sequence      as Seq---- Test--import Test.QuickCheck-import Test.QuickCheck.Poly---- Distribution--import Distribution.TestSuite-import Distribution.TestSuite.QuickCheck---- * Test data generation--instance Arbitrary a => Arbitrary (Seq a) where--    arbitrary = fmap Seq.fromList arbitrary--    shrink seq = map Seq.fromList (shrink (toList seq))---- * Changes---- ** Common changes--instance Arbitrary a => Arbitrary (PrimitiveChange a) where--    arbitrary = frequency [(1, keepGen), (5, replaceGen)] where--        keepGen = return Keep--        replaceGen = fmap ReplaceBy arbitrary--    shrink Keep            = []-    shrink (ReplaceBy val) = Keep : map ReplaceBy (shrink val)--instance Arbitrary p => Arbitrary (MultiChange p) where--    arbitrary = fmap MultiChange.fromList arbitrary--    shrink change = map MultiChange.fromList (shrink (toList change))---- ** Pair changes--deriving instance (Show (DefaultChange a), Show (DefaultChange b)) =>-                  Show (Tuple.AtomicChange a b)--instance (Arbitrary (DefaultChange a), Arbitrary (DefaultChange b)) =>-         Arbitrary (Tuple.AtomicChange a b) where--    arbitrary = oneof [firstGen, secondGen] where--        firstGen = fmap Tuple.First arbitrary--        secondGen = fmap Tuple.Second arbitrary--    shrink (Tuple.First change)  = map Tuple.First (shrink change)-    shrink (Tuple.Second change) = map Tuple.Second (shrink change)---- ** Sequence changes--deriving instance (Show a, Show (DefaultChange a)) => Show (Seq.AtomicChange a)--instance (Arbitrary a, Arbitrary (DefaultChange a)) =>-         Arbitrary (Seq.AtomicChange a) where--    arbitrary = oneof [insertGen, deleteGen, shiftGen, changeAtGen] where--        insertGen = liftA2 Seq.Insert arbitrary arbitrary--        deleteGen = liftA2 Seq.Delete arbitrary arbitrary--        shiftGen = liftA3 Seq.Shift arbitrary arbitrary arbitrary--        changeAtGen = liftA2 Seq.ChangeAt arbitrary arbitrary--    shrink (Seq.Insert ix seq)-        = [Seq.Insert ix' seq'-              | (ix', seq') <- shrink (ix, seq)]-    shrink (Seq.Delete ix len)-        = [Seq.Delete ix' len'-              | (ix', len') <- shrink (ix, len)]-    shrink (Seq.Shift src len tgt)-        = [Seq.Shift src' len' tgt'-              | (src', len', tgt') <- shrink (src, len, tgt)]-    shrink (Seq.ChangeAt ix change)-        = [Seq.ChangeAt ix' change'-              | (ix', change') <- shrink (ix, change)]---- ** Element changes--newtype AtomicAChange = DoubleAndAdd Integer deriving (Show, Arbitrary)--instance Change AtomicAChange where--    type Value AtomicAChange = A--    DoubleAndAdd diff $$ A integer = A (2 * integer + diff)--instance Changeable A where--    type DefaultChange A = MultiChange AtomicAChange--deriving instance Ord A--newtype AtomicBChange = TripleAndAdd Integer deriving (Show, Arbitrary)--instance Change AtomicBChange where--    type Value AtomicBChange = B--    TripleAndAdd diff $$ B integer = B (3 * integer + diff)--instance Changeable B where--    type DefaultChange B = MultiChange AtomicBChange--instance Changeable C---- * Test functions and transformations--testTrans :: A ->> B-testTrans = MultiChange.map $ stateTrans init prop where--    init (A integer) = (B integer, integer)--    prop (DoubleAndAdd diff) state = (change', state') where--        change' = TripleAndAdd (diff - state)--        state' = 2 * state + diff--testFun :: C -> C-testFun = id--testPrdTrans :: A ->> Bool-testPrdTrans = MultiChange.composeMap $ stateTrans init prop where--    init (A integer) = (testPrd integer, integer)--    prop (DoubleAndAdd diff) state = (change', state') where--        change' = ReplaceBy (testPrd state')--        state' = 2 * state + diff--testPrdFun :: C -> Bool-testPrdFun = testPrd . unC--testPrd :: Integer -> Bool-testPrd = (>= 0)--testCompare :: A -> A -> Ordering-testCompare (A integer1) (A integer2) = compare (integer1 `div` 3)-                                                (integer2 `div` 3)---- * Test pattern--transTest :: (Show a, Arbitrary a, Changeable a,-              Show (DefaultChange a), Arbitrary (DefaultChange a),-              Eq b, Changeable b) =>-             String -> (a ->> b) -> (a -> b) -> Test-transTest name trans fun = testProperty name prop where--    prop valAndChanges = map fun (applyChanges valAndChanges) ==-                         applyChanges valAndChanges' where--        valAndChanges' = runTrans trans valAndChanges--applyChanges :: Change p => (Value p, [p]) -> [Value p]-applyChanges (val, changes) = scanl (flip ($$)) val changes
− src/test-suites/TestSuite/Sequence.hs
@@ -1,73 +0,0 @@-module TestSuite.Sequence (--    tests--) where---- Data--import           Data.Foldable (asum)-import           Data.Incremental-import           Data.Sequence (Seq)-import qualified Data.Sequence             as Seq-import qualified Data.Incremental.Sequence as IncSeq---- Test--import Test.QuickCheck-import Test.QuickCheck.Poly---- Distribution--import Distribution.TestSuite---- TestSuite-import TestSuite---- * Tests--tests :: IO [Test]-tests = return [transTest "singleton" IncSeq.singleton-                                      (Seq.singleton :: A -> Seq A),-                transTest "fromPair"  IncSeq.fromPair-                                      (seqFromPair :: (A, A) -> Seq A),-                transTest "cat"       IncSeq.cat-                                      (seqCat :: (Seq A, Seq A) -> Seq A),-                transTest "null"      IncSeq.null-                                      (Seq.null :: Seq A -> Bool),-                transTest "length"    IncSeq.length-                                      (Seq.length :: Seq A -> Int),-                transTest "map"       (IncSeq.map testTrans)-                                      (fmap (toFunction testTrans)),-                transTest "map'"      (IncSeq.map' testFun)-                                      (fmap testFun),-                transTest "concat"    IncSeq.concat-                                      (seqConcat :: Seq (Seq A) -> Seq A),-                transTest "gate"      (IncSeq.gate testPrdTrans)-                                      (seqGate (toFunction testPrdTrans)),-                transTest "gate'"     (IncSeq.gate' testPrdFun)-                                      (seqGate testPrdFun),-                transTest "filter"    (IncSeq.filter testPrdTrans)-                                      (Seq.filter (toFunction testPrdTrans)),-                transTest "filter'"   (IncSeq.filter' testPrdFun)-                                      (Seq.filter testPrdFun),-                transTest "reverse"   IncSeq.reverse-                                      (Seq.reverse :: Seq A -> Seq A),-                transTest "sort"      IncSeq.sort-                                      (Seq.sort :: Seq A -> Seq A),-                transTest "sortBy"    (IncSeq.sortBy testCompare)-                                      (Seq.sortBy testCompare)]--- FIXME: Explain why we have no test for concatMap.--seqFromPair :: (a, a) -> Seq a-seqFromPair (val1, val2) = Seq.fromList [val1, val2]--seqCat :: (Seq a, Seq a) -> Seq a-seqCat = uncurry (Seq.><)--seqConcat :: Seq (Seq a) -> Seq a-seqConcat = asum--seqGate :: (a -> Bool) -> a -> Seq a-seqGate prd val | prd val   = Seq.singleton val-                | otherwise = Seq.empty
+ src/tools/Benchmark.hs view
@@ -0,0 +1,120 @@+module Benchmark (++    runBenchmark++) where++-- Control++import Control.Monad+import Control.DeepSeq+import Control.Exception++-- Data++import           Data.Foldable (toList)+import           Data.MultiChange (MultiChange)+import qualified Data.MultiChange as MultiChange+import           Data.Incremental++-- System++import System.CPUTime++-- Test++import Test.QuickCheck++-- Utilities++import Utilities++{-FIXME:+    Measure cumulative times. For doing so, perform first all recomputations and+    then all adaptions. In each case, measure the start time and the time after+    each step.+-}++-- * Benchmarking++runBenchmark :: (NFData a, Changeable a, NFData (DefaultChange a),+                 NFData b, Changeable b)+             => (a -> b)+             -> (a ->> b)+             -> (a, [DefaultChange a])+             -> IO ()+runBenchmark fun trans src = do+    timePairs <- benchmark fun trans src+    zipWithM_ outputTimePair [0 ..] timePairs++data TimePair = TimePair {+                    recomputeTime :: Integer,+                    adaptTime     :: Integer+                }++benchmark :: (NFData a, Changeable a, NFData (DefaultChange a),+              NFData b, Changeable b)+          => (a -> b)+          -> (a ->> b)+          -> (a, [DefaultChange a])+          -> IO [TimePair]+benchmark fun trans src = do+    fullyEvaluatedSrc <- fullyEvaluate src+    let recomputeResults = recompute fun fullyEvaluatedSrc+    let adaptResults = adapt trans fullyEvaluatedSrc+    recomputeTimes <- getTimes recomputeResults+    adaptTimes <- getTimes adaptResults+    return $ zipWith TimePair recomputeTimes adaptTimes++getTimes :: NFData b => [b] -> IO [Integer]+getTimes results = do+    startTime <- getCPUTime+    let getTime result = do+            fullyEvaluate result+            finishTime <- getCPUTime+            return (finishTime - startTime)+    mapM getTime results++fullyEvaluate :: NFData a => a -> IO a+fullyEvaluate = evaluate . force++outputTimePair :: Int -> TimePair -> IO ()+outputTimePair stepNo timePair = putStrLn $+                                 align stepNoWidth stepNo            +++                                 ": R "                              +++                                 timeOutput (recomputeTime timePair) +++                                 ", A "                              +++                                 timeOutput (adaptTime timePair)++timeOutput :: Integer -> String+timeOutput time = align timeIntegralWidth (inCentiseconds `div` 100) +++                  "."                                                +++                  show (fractionalPart `div` 10)                     +++                  show (fractionalPart `mod` 10)                     +++                  " s" where++    inCentiseconds = (time + 5000000000) `div` 10000000000++    fractionalPart = inCentiseconds `mod` 100++align :: Show a => Int -> a -> String+align width val = Prelude.reverse $+                  take width      $+                  Prelude.reverse (show val) ++ repeat ' '++stepNoWidth :: Int+stepNoWidth = 8++timeIntegralWidth :: Int+timeIntegralWidth = 4++-- * Evaluation of changes++instance NFData a => NFData (PrimitiveChange a) where++    rnf Keep            = ()+    rnf (ReplaceBy val) = val `deepseq` ()++instance NFData p => NFData (MultiChange p) where++    rnf change = rnf (toList change)
+ src/tools/Benchmark/Sequence.hs view
@@ -0,0 +1,117 @@+{-# LANGUAGE UndecidableInstances #-}+module Main (++    main++) where++-- Control++import Control.DeepSeq++-- Data++import           Data.Sequence (Seq)+import qualified Data.Sequence as Seq+import           Data.Incremental+import           Data.Incremental.Sequence as IncSeq++-- Test++import Test.QuickCheck++-- Benchmark++import Benchmark++main :: IO ()+main = do+    performSortBenchmark 10000 10+    performSortBenchmark 100000 10+    performSortBenchmark 1000000 10++-- * Benchmarking++performSortBenchmark :: Int -> Int -> IO ()+performSortBenchmark = performBenchmark (Seq.sort :: Seq Int -> Seq Int)+                                        IncSeq.sort++performBenchmark :: (Arbitrary a, NFData a, Changeable a,+                     DefaultChange a ~ PrimitiveChange a,+                     Arbitrary b, NFData b, Changeable b)+                 => (Seq a -> Seq b)+                 -> (Seq a ->> Seq b)+                 -> Int+                 -> Int+                 -> IO ()+performBenchmark fun trans initLen changeCount = do+    putStrLn $ "Length of initial sequence: " ++ show initLen+    putStrLn $ "Number of changes:          " ++ show changeCount+    src <- generate $ srcGen initLen changeCount+    runBenchmark fun trans src++-- * Benchmark data generation++srcGen :: (Arbitrary a, Changeable a, DefaultChange a ~ PrimitiveChange a)+       => Int+       -> Int+       -> Gen (Seq a, [DefaultChange (Seq a)])+srcGen initLen changeCount = do+    seq <- seqGen initLen+    changes <- changesGen initLen changeCount+    return (seq, changes) where++    changesGen len changeCount+        | changeCount == 0 = return []+        | otherwise        = do+            (change, lenDiff) <- changeAndLengthDiffGen len+            changes <- changesGen (len + lenDiff) (pred changeCount)+            return (change : changes)++-- | Generates a sequence of the given length.+seqGen :: Arbitrary a => Int -> Gen (Seq a)+seqGen len = do+    elems <- vectorOf len arbitrary+    return (Seq.fromList elems)++{-|+    Generates a sequence change that deals with only a single element and stays+    within the bounds of the sequence, along with the change in length that this+    change causes.+-}+changeAndLengthDiffGen :: (Arbitrary a,+                           Changeable a,+                           DefaultChange a ~ PrimitiveChange a)+                       => Int+                       -> Gen (DefaultChange (Seq a), Int)+changeAndLengthDiffGen len+    | len == 0  = insertGen+    | otherwise = oneof [insertGen, deleteGen, shiftGen, changeAtGen] where++    insertGen = do+        ix <- choose (0, len)+        elem <- arbitrary+        return (insert ix (Seq.singleton elem), 1)++    deleteGen = do+        ix <- choose (0, pred len)+        return (delete ix 1, -1)++    shiftGen = do+        src <- choose (0, pred len)+        tgt <- choose (0, pred len)+        return (shift src 1 tgt, 0)++    changeAtGen = do+        ix <- choose (0, pred len)+        newElem <- arbitrary+        return (changeAt ix (ReplaceBy newElem), 0)++-- * Evaluation of changes++instance (NFData a, NFData (DefaultChange a)) => NFData (AtomicChange a) where++    rnf (Insert ix seq)      = ix `deepseq` seq `deepseq` ()+    rnf (Delete ix len)      = ix `deepseq` len `deepseq` ()+    rnf (Shift src len tgt)  = src `deepseq` len `deepseq` tgt `deepseq` ()+    rnf (ChangeAt ix change) = ix `deepseq` change `deepseq` ()
+ src/tools/TestSuite.hs view
@@ -0,0 +1,200 @@+{-# LANGUAGE UndecidableInstances #-}+module TestSuite (++    -- * Changes++    AtomicAChange (DoubleAndAdd),+    AtomicBChange (TripleAndAdd),++    -- * Test functions and transformations++    testTrans,+    testFun,+    testPrdTrans,+    testPrdFun,+    testCompare,++    -- * Test pattern++    transTest++) where++-- Prelude++import Prelude hiding (id, (.))++-- Control++import Control.Category+import Control.Applicative++-- Data++import           Data.Foldable (toList)+import           Data.MultiChange (MultiChange)+import qualified Data.MultiChange               as MultiChange+import           Data.Sequence (Seq)+import qualified Data.Sequence                  as Seq+import           Data.Incremental+import qualified Data.Incremental.Tuple         as Tuple+import qualified Data.Incremental.Sequence      as Seq++-- Test++import Test.QuickCheck+import Test.QuickCheck.Poly++-- Distribution++import Distribution.TestSuite+import Distribution.TestSuite.QuickCheck++-- Utilities++import Utilities++-- * Changes++-- ** Common changes++instance Arbitrary a => Arbitrary (PrimitiveChange a) where++    arbitrary = frequency [(1, keepGen), (5, replaceGen)] where++        keepGen = return Keep++        replaceGen = fmap ReplaceBy arbitrary++    shrink Keep            = []+    shrink (ReplaceBy val) = Keep : map ReplaceBy (shrink val)++instance Arbitrary p => Arbitrary (MultiChange p) where++    arbitrary = fmap MultiChange.fromList arbitrary++    shrink change = map MultiChange.fromList (shrink (toList change))++-- ** Pair changes++deriving instance (Show (DefaultChange a), Show (DefaultChange b)) =>+                  Show (Tuple.AtomicChange a b)++instance (Arbitrary (DefaultChange a), Arbitrary (DefaultChange b)) =>+         Arbitrary (Tuple.AtomicChange a b) where++    arbitrary = oneof [firstGen, secondGen] where++        firstGen = fmap Tuple.First arbitrary++        secondGen = fmap Tuple.Second arbitrary++    shrink (Tuple.First change)  = map Tuple.First (shrink change)+    shrink (Tuple.Second change) = map Tuple.Second (shrink change)++-- ** Sequence changes++deriving instance (Show a, Show (DefaultChange a)) => Show (Seq.AtomicChange a)++instance (Arbitrary a, Arbitrary (DefaultChange a)) =>+         Arbitrary (Seq.AtomicChange a) where++    arbitrary = oneof [insertGen, deleteGen, shiftGen, changeAtGen] where++        insertGen = liftA2 Seq.Insert arbitrary arbitrary++        deleteGen = liftA2 Seq.Delete arbitrary arbitrary++        shiftGen = liftA3 Seq.Shift arbitrary arbitrary arbitrary++        changeAtGen = liftA2 Seq.ChangeAt arbitrary arbitrary++    shrink (Seq.Insert ix seq)+        = [Seq.Insert ix' seq'+              | (ix', seq') <- shrink (ix, seq)]+    shrink (Seq.Delete ix len)+        = [Seq.Delete ix' len'+              | (ix', len') <- shrink (ix, len)]+    shrink (Seq.Shift src len tgt)+        = [Seq.Shift src' len' tgt'+              | (src', len', tgt') <- shrink (src, len, tgt)]+    shrink (Seq.ChangeAt ix change)+        = [Seq.ChangeAt ix' change'+              | (ix', change') <- shrink (ix, change)]++-- ** Element changes++newtype AtomicAChange = DoubleAndAdd Integer deriving (Show, Arbitrary)++instance Change AtomicAChange where++    type Value AtomicAChange = A++    DoubleAndAdd diff $$ A integer = A (2 * integer + diff)++instance Changeable A where++    type DefaultChange A = MultiChange AtomicAChange++deriving instance Ord A++newtype AtomicBChange = TripleAndAdd Integer deriving (Show, Arbitrary)++instance Change AtomicBChange where++    type Value AtomicBChange = B++    TripleAndAdd diff $$ B integer = B (3 * integer + diff)++instance Changeable B where++    type DefaultChange B = MultiChange AtomicBChange++instance Changeable C++-- * Test functions and transformations++testTrans :: A ->> B+testTrans = MultiChange.map $ stateTrans init prop where++    init (A integer) = (B integer, integer)++    prop (DoubleAndAdd diff) state = (change', state') where++        change' = TripleAndAdd (diff - state)++        state' = 2 * state + diff++testFun :: C -> C+testFun = id++testPrdTrans :: A ->> Bool+testPrdTrans = MultiChange.composeMap $ stateTrans init prop where++    init (A integer) = (testPrd integer, integer)++    prop (DoubleAndAdd diff) state = (change', state') where++        change' = ReplaceBy (testPrd state')++        state' = 2 * state + diff++testPrdFun :: C -> Bool+testPrdFun = testPrd . unC++testPrd :: Integer -> Bool+testPrd = (>= 0)++testCompare :: A -> A -> Ordering+testCompare (A integer1) (A integer2) = compare (integer1 `div` 3)+                                                (integer2 `div` 3)++-- * Test pattern++transTest :: (Show a, Arbitrary a, Changeable a,+              Show (DefaultChange a), Arbitrary (DefaultChange a),+              Eq b, Changeable b) =>+             String -> (a ->> b) -> (a -> b) -> Test+transTest name trans fun = testProperty name prop where++    prop src = recompute fun src == adapt trans src
+ src/tools/TestSuite/Sequence.hs view
@@ -0,0 +1,74 @@+module TestSuite.Sequence (++    tests++) where++-- Data++import           Data.Foldable (asum)+import           Data.Incremental+import           Data.Sequence (Seq)+import qualified Data.Sequence             as Seq+import qualified Data.Incremental.Sequence as IncSeq++-- Test++import Test.QuickCheck+import Test.QuickCheck.Poly++-- Distribution++import Distribution.TestSuite++-- TestSuite++import TestSuite++-- * Tests++tests :: IO [Test]+tests = return [{-transTest "singleton" IncSeq.singleton+                                      (Seq.singleton :: A -> Seq A),+                transTest "fromPair"  IncSeq.fromPair+                                      (seqFromPair :: (A, A) -> Seq A),+                transTest "cat"       IncSeq.cat+                                      (seqCat :: (Seq A, Seq A) -> Seq A),+                transTest "null"      IncSeq.null+                                      (Seq.null :: Seq A -> Bool),+                transTest "length"    IncSeq.length+                                      (Seq.length :: Seq A -> Int),+                transTest "map"       (IncSeq.map testTrans)+                                      (fmap (toFunction testTrans)),+                transTest "map'"      (IncSeq.map' testFun)+                                      (fmap testFun),+                transTest "concat"    IncSeq.concat+                                      (seqConcat :: Seq (Seq A) -> Seq A),+                transTest "gate"      (IncSeq.gate testPrdTrans)+                                      (seqGate (toFunction testPrdTrans)),+                transTest "gate'"     (IncSeq.gate' testPrdFun)+                                      (seqGate testPrdFun),+                transTest "filter"    (IncSeq.filter testPrdTrans)+                                      (Seq.filter (toFunction testPrdTrans)),+                transTest "filter'"   (IncSeq.filter' testPrdFun)+                                      (Seq.filter testPrdFun),+                transTest "reverse"   IncSeq.reverse+                                      (Seq.reverse :: Seq A -> Seq A),+                transTest "sort"      IncSeq.sort+                                      (Seq.sort :: Seq A -> Seq A),+                transTest "sortBy"    (IncSeq.sortBy testCompare)+                                      (Seq.sortBy testCompare)-}]+-- FIXME: Explain why we have no test for concatMap.++seqFromPair :: (a, a) -> Seq a+seqFromPair (val1, val2) = Seq.fromList [val1, val2]++seqCat :: (Seq a, Seq a) -> Seq a+seqCat = uncurry (Seq.><)++seqConcat :: Seq (Seq a) -> Seq a+seqConcat = asum++seqGate :: (a -> Bool) -> a -> Seq a+seqGate prd val | prd val   = Seq.singleton val+                | otherwise = Seq.empty
+ src/tools/Utilities.hs view
@@ -0,0 +1,23 @@+module Utilities (++    recompute,+    adapt++) where++-- Data++import Data.Incremental++recompute :: (Changeable a, Changeable b)+          => (a -> b)+          -> (a, [DefaultChange a]) -> [b]+recompute fun src = map fun (applyChanges src)++adapt :: (Changeable a, Changeable b)+      => (a ->> b)+      -> (a, [DefaultChange a]) -> [b]+adapt trans src = applyChanges (runTrans trans src)++applyChanges :: Change p => (Value p, [p]) -> [Value p]+applyChanges (val, changes) = scanl (flip ($$)) val changes