keera-hails-reactivevalues 0.5.0 → 0.6.0
raw patch · 2 files changed
+144/−83 lines, 2 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- keera-hails-reactivevalues.cabal +1/−1
- src/Data/ReactiveValue.hs +143/−82
keera-hails-reactivevalues.cabal view
@@ -6,7 +6,7 @@ build-type: Simple name: keera-hails-reactivevalues-version: 0.5.0+version: 0.6.0 author: Ivan Perez maintainer: support@keera.co.uk homepage: http://www.keera.co.uk/blog/community/
src/Data/ReactiveValue.hs view
@@ -1,33 +1,87 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FunctionalDependencies #-}--- | Reactive Values (RVs) are typed mutable variables with a change--- notification mechanism.+-- | ----- They are defined by providing a way to read the value, a way to change it,--- and a way to install an event listener when the value has changed.+-- Copyright : (C) Keera Studios Ltd, 2013+-- License : BSD3+-- Maintainer : support@keera.co.uk ----- RVs are pruposely abstract, defined as a type class. GUI toolkits,--- for instance, can use existing event-handling installing mechanisms to--- enclose widget attributes as Reactive Values, without the need for an--- additional, manually-handled event dispatcher.+-- /Reactive Values/ (RVs) are typed mutable variables with a change+-- notification mechanism. They are defined by providing a way to /read/ the+-- value, a way to /change/ it, and a way to install an /react/ when the value+-- has changed. ----- RVs are complemented with /relation-building/ functions, which--- enable pairing RVs during execution so that they are /kept in/--- /sync/ for the duration of the program.+-- RVs are abstract (i.e., a type class). This module defines a class and+-- manipulation operations, but you need an actual instance of RV underneath.+-- For a way to turn 'IORef's into RVs, see the example below. GUI toolkits can+-- use existing event-handling mechanisms to make widget attributes Reactive+-- Values without additional boilerplate. A number of+-- <https://github.com/keera-studios/keera-hails backends> (GUIs, devices,+-- files, network, FRP) are supported. ----- This module only defines RVs and operations on them. For connections--- to existing backends (GUIs, devices, files, network, FRP), see--- https://github.com/keera-studios/keera-hails+-- RVs are complemented with /Reactive Relations/, which connect RVs and keep+-- them /in sync/ during execution. ----- A more detailed description of reactive values can be found at:--- http://dl.acm.org/citation.cfm?id=2804316+-- A very simple example of an RV is the following construction, in+-- which passive IORefs are turned into active Reactive Values. ----- Copyright : (C) Keera Studios Ltd, 2013--- License : BSD3--- Maintainer : support@keera.co.uk+-- @+-- import Control.Concurrent (threadDelay)+-- import Control.Monad (forever)+--+-- -- From the package keera-callbacks+-- import Data.CBRef (installCallbackCBRef, newCBRef, readCBRef,+-- writeCBRef)+--+-- -- From keera-hails-reactivevalues+-- import Data.ReactiveValue (ReactiveFieldReadWrite (..), ReactiveFieldWrite,+-- reactiveValueModify, wrapMW, (=:>))+--+-- main :: IO ()+-- main = do+--+-- -- Empower IORef with callback installation mechanism+-- --+-- -- passiveCBRef :: CBRRef Integer+-- passiveCBRef <- newCBRef 0+--+-- -- Turn IORef into active reactive value (RV).+-- --+-- -- We use the type of Reactive Fields, which have a trivial RV implementation.+-- let activeCBRefRV :: ReactiveFieldReadWrite IO Integer+-- activeCBRefRV = ReactiveFieldReadWrite+-- (writeCBRef passiveCBRef)+-- (readCBRef passiveCBRef)+-- (installCallbackCBRef passiveCBRef)+--+-- -- Define a write-only RV that prints whatever you put in it.+-- let printer :: Show a => ReactiveFieldWrite IO a+-- printer = wrapMW print+--+-- -- Connect them using a reactive rule. In a GUI application, this code would+-- -- in the controller, and would define connections between the model and+-- -- the view.+-- --+-- -- For bi-directional connections, see (=:=).+-- activeCBRefRV =:> printer+--+-- -- To demonstrate the connection, just loop forever and increment the+-- -- first reactive value. The change will propagate through the channel+-- -- and be printed on the screen every second.+-- forever $ do+-- threadDelay 1000000 -- 1 second+-- reactiveValueModify activeCBRefRV (+1)+-- @+--+-- For further explanations on reactive values, see the+-- <http://dl.acm.org/citation.cfm?id=2804316 Haskell Symposium paper> and+-- <https://github.com/keera-studios/keera-hails/tree/develop/demos the demos>+-- in our repository.+ module Data.ReactiveValue ( -- * Reactive Values+ -- $rvs -- ** Readable Reactive Values -- $readablervs@@ -50,30 +104,22 @@ , (=:=) , (<:=) - -- * Activatable Reactive Values - -- $activatable- , ReactiveFieldActivatable- , ReactiveValueActivatable(..)- , mkActivatable-- -- * Purely functional implementation of RVs.+ -- * Reactive Fields (pure RVs) -- $fields , ReactiveFieldRead(..) , ReactiveFieldWrite(..) , ReactiveFieldReadWrite(..) - -- ** Setters, getters and notifiers- -- $settersgetters , FieldGetter , FieldSetter , FieldNotifier - -- * RV combinators+ -- * RV creation and manipulation - -- ** Creating, lifting on and manipulating readable values+ -- ** Readable RVs -- $readablecombinators , constR@@ -87,12 +133,10 @@ , wrapMR , wrapMRPassive , eventR-- -- *** Merging , lMerge , rMerge - -- ** Creating, lifting on and manipulating writeable values+ -- ** Writable RVs -- $writablecombinators , constW@@ -106,11 +150,13 @@ , wrapDo_ - -- ** Lift monadic actions/sinks (setters) and sources (getters)-- -- *** Lifting (sink) computations into writable RVs.+ -- ** Read-write RVs -- $readwritecombinators+ , liftRW+ , liftRW2+ , pairRW+ , modRW -- **** Bijective functions , BijectiveFunc@@ -120,34 +166,35 @@ , Involution , involution - -- **** Combinators- , liftRW- , liftRW2- , pairRW- , modRW+ -- **** Low-level operations , reactiveValueModify - -- * Stopping change+ -- * Controlling change -- $changecontrol - -- ** Stopping unnecesary change propagation+ -- ** Stopping change propagation , eqCheck-- -- ** Stopping all change propagation , passivelyR , passivelyRW - -- ** Changing control over change propagation+ -- ** Governing , governingR , governingRW - -- ** Conditional change propagation+ -- ** Guarding , ifRW , ifRW_ , guardRO , guardRO'++ -- * Activatable RVs++ -- $activatable+ , ReactiveValueActivatable(..)+ , ReactiveFieldActivatable+ , mkActivatable ) where @@ -156,6 +203,27 @@ -- in the source category import Data.Functor.Contravariant +-- $rvs+--+-- Reactive Values are an abstraction over values that change over the execution+-- of a program, and whose change we can be aware of.+--+-- There is no unique, canonical implementation of RVs: they are defined as+-- a collection of type classes, and you are free to make your existing+-- framework reactive by providing the necessary instances.+--+-- RVs are distinguished by the API they offer, mainly whether it is possible+-- to read them, to write to them, or both. A /readable/ RV is one that whose+-- value we can read (whether it is read-only or read-write, or whether it will+-- actively propagate changes to it or not, is a different matter). Analogously,+-- a /writable/ RV is one that we can write to (write-only or read-write).+--+-- We also distinguish between /active/ RVs (i.e., those that actively propagate+-- changes through the Reactive Relations they are connected to) and /passive/+-- RVs (those that do not propagate changes). It is possible to "silence" an+-- RV by minimizing unnecesssary change, or attaching it to another RV that+-- determines when change propagates (see governing and guarding below).+ -- $readablervs -- -- Readable reactive values are mutable values that can be read and, possibly,@@ -250,6 +318,16 @@ -- | Pairs of a monadic action and a parametric monadic action are also RVs instance (Functor m, Monad m) => ReactiveValueReadWrite (m a, a -> m b) a m +-- $activatable+--+-- Activatable RVs are values that never hold any data, but whose change (or+-- activation, or some sort of internal event) we need to be aware of).++-- | A class for things with a trivial field that carries unit. Buttons+-- (in any GUI library), for instance, could be a member of this class.+class ReactiveValueActivatable m a where+ defaultActivation :: a -> ReactiveFieldActivatable m+ -- $rules -- -- Reactive Rules are data dependency (data-passing) building combinators.@@ -290,22 +368,6 @@ -- where sync1 = reactiveValueRead v1 >>= reactiveValueWrite v2 -- sync2 = reactiveValueRead v2 >>= reactiveValueWrite v1 --- $settersgetters------ These are used internally for combinators that need to return RV instances. They can--- also be used to write new backends and library extensions, but they are not--- recommended to enclose application models. For that purpose, see light models and--- protected models instead.---- | The type of a monadic value producer (a getter, a source).-type FieldGetter m a = m a---- | The type of a monadic value consumer (a setter, a sink, a slot).-type FieldSetter m a = a -> m ()---- | The type of an event handler installer-type FieldNotifier m a = m () -> m () -- FIXME: why does fieldnotifier have an argument- -- $fields -- This is a specific implementation of RVs that does not have a custom event queue. --@@ -325,6 +387,10 @@ data ReactiveFieldReadWrite m a = ReactiveFieldReadWrite (FieldSetter m a) (FieldGetter m a) (FieldNotifier m a) +-- | A trivial type for Readable RVs that carry unit. They can be used for+-- buttons, or events without data.+type ReactiveFieldActivatable m = ReactiveFieldRead m ()+ instance Monad m => ReactiveValueRead (ReactiveFieldRead m a) a m where reactiveValueOnCanRead (ReactiveFieldRead _ notifier) = notifier reactiveValueRead (ReactiveFieldRead getter _) = getter@@ -341,36 +407,31 @@ instance Monad m => ReactiveValueReadWrite (ReactiveFieldReadWrite m a) a m --- $activatable+-- $settersgetters ----- Activatable RVs are values that never hold any data, but whose change (or--- activation, or some sort of internal event) we need to be aware of).+-- These are used internally for combinators that need to return RV instances. They can+-- also be used to write new backends and library extensions, but they are not+-- recommended to enclose application models. For that purpose, see light models and+-- protected models instead. --- | A class for things with a trivial field that carries unit. Buttons--- (in any GUI library), for instance, could be a member of this class.-class ReactiveValueActivatable m a where- defaultActivation :: a -> ReactiveFieldActivatable m+-- | The type of a monadic value producer (a getter, a source).+type FieldGetter m a = m a --- | A trivial type for Readable RVs that carry unit. They can be used for--- buttons, or events without data.-type ReactiveFieldActivatable m = ReactiveFieldRead m ()+-- | The type of a monadic value consumer (a setter, a sink, a slot).+type FieldSetter m a = a -> m () +-- | The type of an event handler installer+type FieldNotifier m a = m () -> m () -- FIXME: why does fieldnotifier have an argument+ -- | Create an activatable RV from a handler installer. mkActivatable :: Monad m => (m () -> m ()) -> ReactiveFieldActivatable m mkActivatable f = ReactiveFieldRead getter notifier where getter = return () notifier = f --- instance (ReactiveValueWrite a b) => ReactiveValueWrite (TypedReactiveValue a b) b where--- reactiveValueWrite (TypedReactiveValue x _) v = reactiveValueWrite x v------ instance (ReactiveValueRead a b) => ReactiveValueRead (TypedReactiveValue a b) b where--- reactiveValueOnCanRead (TypedReactiveValue x _) v op = (reactiveValueOnCanRead x) v op--- reactiveValueRead (TypedReactiveValue x _) = reactiveValueRead x- -- $readablecombinators --- | A trivial RV builder tith a constant value. We need this because+-- | A trivial RV builder with a constant value. We need this because -- we cannot have overlapping instances with a default case, and because -- the interpretation of lifting with RVs could be very confusing unless -- values are lifted into RVs explicitly.@@ -595,7 +656,7 @@ -- | Apply a modification to an RV. This modification is not attached to -- the RV, and there are no guarantees that it will be atomic (if you need--- atomicity, check out STM.+-- atomicity, check out STM). reactiveValueModify :: (Monad m, ReactiveValueReadWrite a b m) => a -> (b -> b) -> m () reactiveValueModify r f = reactiveValueWrite r . f =<< reactiveValueRead r