sodium 0.6.0.2 → 0.7.0.0
raw patch · 6 files changed
+88/−16 lines, 6 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ FRP.Sodium: split :: Event [a] -> Event a
+ FRP.Sodium.Context: split :: Context r => Event r [a] -> Event r a
Files
- examples/games/poodle.hs +1/−1
- examples/tests/unit-tests.hs +25/−1
- sodium.cabal +23/−10
- src/FRP/Sodium.hs +1/−0
- src/FRP/Sodium/Context.hs +6/−0
- src/FRP/Sodium/Plain.hs +32/−4
examples/games/poodle.hs view
@@ -4,7 +4,7 @@ -- stb-image -- OpenGL -- GLUT-import FRP.Sodium+import FRP.Sodium hiding (split) import Control.Applicative import Control.Monad.Trans import Data.Maybe
examples/tests/unit-tests.hs view
@@ -526,12 +526,36 @@ unlisten assertEqual "coalesce1" [2, 11] =<< readIORef outRef +split1 = TestCase $ do+ outRef <- newIORef []+ (ea, pushA) <- sync newEvent+ let ewords = coalesce (++) $ split $ words <$> ea+ unlisten <- sync $ listen ewords $ \o -> modifyIORef outRef (++ [o])+ sync $ pushA "the common cormorant"+ sync $ pushA "or shag"+ unlisten+ assertEqual "split1" ["the","common","cormorant","or","shag"] =<< readIORef outRef++split2 = TestCase $ do+ outRef <- newIORef []+ (ea, pushA) <- sync newEvent+ let halve [] = []+ halve [_] = []+ halve str = [take (length str `div` 2) str,+ drop (length str `div` 2) str]+ ehalves = split $ (halve <$> ea) `merge` (halve <$> ehalves)+ unlisten <- sync $ listen ehalves $ \o -> modifyIORef outRef (++ [o])+ sync $ pushA "abcdefgh"+ unlisten+ assertEqual "split2" ["abcd","ab","a","b","cd","c","d",+ "efgh","ef","e","f","gh","g","h"] =<< readIORef outRef+ tests = test [ event1, fmap1, merge1, filterJust1, filterE1, gate1, beh1, beh2, beh3, beh4, beh5, behConstant, valuesThenMap, valuesTwiceThenMap, valuesThenCoalesce, valuesTwiceThenCoalesce, valuesThenSnapshot, valuesTwiceThenSnapshot, valuesThenMerge, valuesThenFilter, valuesTwiceThenFilter, valuesThenOnce, valuesTwiceThenOnce, valuesLateListen, holdIsDelayed, appl1, snapshot1, count1, collect1, collect2, collectE1, collectE2, switchE1,- switch1, once1, once2, cycle1{-, mergeWith1, mergeWith2, mergeWith3,+ switch1, once1, once2, cycle1, split1, split2 {-, mergeWith1, mergeWith2, mergeWith3, coalesce1-} ] main = {-forever $ -} runTestTT tests
sodium.cabal view
@@ -1,5 +1,5 @@ name: sodium-version: 0.6.0.2+version: 0.7.0.0 synopsis: Sodium Reactive Programming (FRP) System description: A general purpose Reactive Programming (FRP) system. This is part of a project to@@ -20,15 +20,28 @@ . See the /examples/ directory for test cases and examples. .- Changes: 0.2.0.0 Fix some value recursion deadlocks and improve docs;- 0.3.0.0 Add mergeWith, make cross asynchronous;- 0.4.0.0 API revamp to remove an excess type variable. Parallelism stuff to be rethought;- 0.5.0.0 Improved tests cases + add Freecell example, API tweaks;- 0.5.0.1 Internal improvements;- 0.5.0.2 Fix multiple memory leaks;- 0.6 Minor API changes, particular with accum;- 0.6.0.1 ghc-7.8 compatibility;- 0.6.0.2 Fix memory leak - see memory-test-8 & memory-test-8a.+ Changes:+ .+ * 0.2.0.0 - Fix some value recursion deadlocks and improve docs;+ .+ * 0.3.0.0 - Add mergeWith, make cross asynchronous;+ .+ * 0.4.0.0 - API revamp to remove an excess type variable. Parallelism stuff to be rethought;+ .+ * 0.5.0.0 - Improved tests cases + add Freecell example, API tweaks;+ .+ * 0.5.0.1 - Internal improvements;+ .+ * 0.5.0.2 - Fix multiple memory leaks;+ .+ * 0.6 - Minor API changes, particular with accum;+ .+ * 0.6.0.1 - ghc-7.8 compatibility;+ .+ * 0.6.0.2 - Fix memory leak - see memory-test-8 & memory-test-8a;+ .+ * 0.7.0.0 - Add split primitive.+ license: BSD3 license-file: LICENSE author: Stephen Blackheath
src/FRP/Sodium.hs view
@@ -55,6 +55,7 @@ sample, coalesce, once,+ split, -- * Derived FRP functions mergeWith, filterE,
src/FRP/Sodium/Context.hs view
@@ -82,6 +82,12 @@ coalesce :: (a -> a -> a) -> Event r a -> Event r a -- | Throw away all event occurrences except for the first one. once :: Context r => Event r a -> Event r a+ -- | Take each list item and put it into a new transaction of its own.+ --+ -- An example use case of this might be a situation where we are splitting+ -- a block of input data into frames. We obviously want each frame to have+ -- its own transaction so that state is updated separately each frame.+ split :: Event r [a] -> Event r a -- | A time-varying value, British spelling. type Behaviour r a = Behavior r a
src/FRP/Sodium/Plain.hs view
@@ -24,7 +24,7 @@ import Data.Maybe import Data.Set (Set) import qualified Data.Set as S-import Data.Sequence (Seq, (|>))+import Data.Sequence (Seq, (|>), (><)) import qualified Data.Sequence as Seq import GHC.Exts import System.Mem.Weak@@ -126,6 +126,7 @@ sample = sample coalesce = coalesce once = once+ split = split -- | An event that gives the updates for the behavior. If the behavior was created -- with 'hold', then 'changes' gives you back the event that was passed to 'hold'.@@ -164,6 +165,13 @@ loop else return ()+ post <- gets asPost+ unless (Seq.null post) $ do+ let Reactive task = post `Seq.index` 0+ modify $ \as -> as { asPost = Seq.drop 1 post }+ task+ loop+ outVar <- newIORef undefined let lock = paLock partition putMVar lock ()@@ -171,7 +179,8 @@ evalStateT loop $ ReactiveState { asQueue1 = Seq.singleton (task >>= ioReactive . writeIORef outVar), asQueue2 = q,- asFinal = Seq.empty+ asFinal = Seq.empty,+ asPost = Seq.empty } takeMVar lock readIORef outVar@@ -386,6 +395,21 @@ return unlisten addCleanup_Listen unlistener l +-- | Take each list item and put it into a new transaction of its own.+--+-- An example use case of this might be a situation where we are splitting+-- a block of input data into frames. We obviously want each frame to have+-- its own transaction so that state is updated separately each frame.+split :: Event [a] -> Event a+split esa = Event gl cacheRef (dep esa)+ where+ cacheRef = unsafeNewIORef Nothing esa+ gl = do+ (l, push, nodeRef) <- ioReactive newEventImpl+ unlistener <- later $ linkedListen esa (Just nodeRef) False $ \as ->+ schedulePost $ map push as+ addCleanup_Listen unlistener l+ -- | Create a new 'Behavior' along with an action to push changes into it. -- American spelling. newBehavior :: a -- ^ Initial behavior value@@ -502,7 +526,8 @@ data ReactiveState = ReactiveState { asQueue1 :: Seq (Reactive ()), asQueue2 :: PriorityQueue (Maybe (MVar Node)) (Reactive ()),- asFinal :: Seq (Reactive ())+ asFinal :: Seq (Reactive ()),+ asPost :: Seq (Reactive ()) } instance Functor (R.Reactive Plain) where@@ -541,6 +566,9 @@ scheduleLast :: Reactive () -> Reactive () scheduleLast task = Reactive $ modify $ \as -> as { asFinal = asFinal as |> task } +schedulePost :: [Reactive ()] -> Reactive ()+schedulePost tasks = Reactive $ modify $ \as -> as { asPost = Seq.fromList tasks >< asPost as }+ data Listen a = Listen { runListen_ :: Maybe (MVar Node) -> Bool -> (a -> Reactive ()) -> Reactive (IO ()) } -- | Unwrap an event's listener machinery.@@ -626,7 +654,7 @@ let listeners' = M.delete iD (noListeners no) return $ listeners' `seq` no { noListeners = listeners' } -data Dep = Dep Any+newtype Dep = Dep Any dep :: a -> Dep dep = Dep . unsafeCoerce