Skip to content

Commit

Permalink
Merge pull request #175 from mitchellwrosen/type-sigs
Browse files Browse the repository at this point in the history
Add more type signatures for readability
  • Loading branch information
HeinrichApfelmus authored May 16, 2018
2 parents 0177b5e + 03f608a commit a60e40b
Show file tree
Hide file tree
Showing 14 changed files with 129 additions and 50 deletions.
9 changes: 5 additions & 4 deletions reactive-banana/src/Control/Event/Handler.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module Control.Event.Handler (
-- * Synopsis
-- | <http://en.wikipedia.org/wiki/Event-driven_programming Event-driven programming>
-- in the traditional imperative style.

-- * Documentation
Handler, AddHandler(..), newAddHandler,
mapIO, filterIO,
Expand All @@ -24,10 +24,10 @@ type Handler a = a -> IO ()

-- | The type 'AddHandler' represents a facility for registering
-- event handlers. These will be called whenever the event occurs.
--
--
-- When registering an event handler, you will also be given an action
-- that unregisters this handler again.
--
--
-- > do unregisterMyHandler <- register addHandler myHandler
--
newtype AddHandler a = AddHandler { register :: Handler a -> IO (IO ()) }
Expand All @@ -40,7 +40,7 @@ instance Functor AddHandler where

-- | Map the event value with an 'IO' action.
mapIO :: (a -> IO b) -> AddHandler a -> AddHandler b
mapIO f e = AddHandler $ \h -> register e $ \x -> f x >>= h
mapIO f e = AddHandler $ \h -> register e $ \x -> f x >>= h

-- | Filter event values that don't return 'True'.
filterIO :: (a -> IO Bool) -> AddHandler a -> AddHandler a
Expand Down Expand Up @@ -71,4 +71,5 @@ newAddHandler = do
mapM_ ($ a) . map snd . Map.toList =<< readIORef handlers
return (AddHandler register, runHandlers)

atomicModifyIORef_ :: IORef a -> (a -> a) -> IO ()
atomicModifyIORef_ ref f = atomicModifyIORef ref $ \x -> (f x, ())
21 changes: 18 additions & 3 deletions reactive-banana/src/Control/Monad/Trans/RWSIO.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module Control.Monad.Trans.RWSIO (
-- * Synopsis
-- | An implementation of the reader/writer/state monad transformer
-- using an 'IORef'.

-- * Documentation
RWSIOT(..), Tuple(..), rwsT, runRWSIOT, tell, ask, get, put,
) where
Expand All @@ -27,7 +27,7 @@ instance Functor m => Functor (RWSIOT r w s m) where fmap = fmapR
instance Applicative m => Applicative (RWSIOT r w s m) where
pure = pureR
(<*>) = apR

instance Monad m => Monad (RWSIOT r w s m) where
return = returnR
(>>=) = bindR
Expand All @@ -39,13 +39,28 @@ instance MonadTrans (RWSIOT r w s) where lift = liftR
{-----------------------------------------------------------------------------
Functions
------------------------------------------------------------------------------}
liftIOR :: MonadIO m => IO a -> RWSIOT r w s m a
liftIOR m = R $ \_ -> liftIO m

liftR :: m a -> RWSIOT r w s m a
liftR m = R $ \_ -> m

fmapR :: Functor m => (a -> b) -> RWSIOT r w s m a -> RWSIOT r w s m b
fmapR f m = R $ \x -> fmap f (run m x)

returnR :: Monad m => a -> RWSIOT r w s m a
returnR a = R $ \_ -> return a

bindR :: Monad m => RWSIOT r w s m a -> (a -> RWSIOT r w s m b) -> RWSIOT r w s m b
bindR m k = R $ \x -> run m x >>= \a -> run (k a) x

mfixR :: MonadFix m => (a -> RWSIOT r w s m a) -> RWSIOT r w s m a
mfixR f = R $ \x -> mfix (\a -> run (f a) x)

pureR :: Applicative m => a -> RWSIOT r w s m a
pureR a = R $ \_ -> pure a

apR :: Applicative m => RWSIOT r w s m (a -> b) -> RWSIOT r w s m a -> RWSIOT r w s m b
apR f a = R $ \x -> run f x <*> run a x

rwsT :: (MonadIO m, Monoid w) => (r -> s -> IO (a, s, w)) -> RWSIOT r w s m a
Expand All @@ -60,7 +75,7 @@ rwsT f = do
runRWSIOT :: (MonadIO m, Monoid w) => RWSIOT r w s m a -> (r -> s -> m (a,s,w))
runRWSIOT m r s = do
w' <- liftIO $ newIORef mempty
s' <- liftIO $ newIORef s
s' <- liftIO $ newIORef s
a <- run m (Tuple r w' s')
s <- liftIO $ readIORef s'
w <- liftIO $ readIORef w'
Expand Down
12 changes: 10 additions & 2 deletions reactive-banana/src/Control/Monad/Trans/ReaderWriterIO.hs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module Control.Monad.Trans.ReaderWriterIO (
-- * Synopsis
-- | An implementation of the reader/writer monad transformer
-- using an 'IORef' for the writer.

-- * Documentation
ReaderWriterIOT, readerWriterIOT, runReaderWriterIOT, tell, listen, ask, local,
) where
Expand All @@ -27,7 +27,7 @@ instance Functor m => Functor (ReaderWriterIOT r w m) where fmap = fmapR
instance Applicative m => Applicative (ReaderWriterIOT r w m) where
pure = pureR
(<*>) = apR

instance Monad m => Monad (ReaderWriterIOT r w m) where
return = returnR
(>>=) = bindR
Expand All @@ -46,20 +46,28 @@ instance (Monad m, a ~ ()) => Monoid (ReaderWriterIOT r w m a) where
{-----------------------------------------------------------------------------
Functions
------------------------------------------------------------------------------}
liftIOR :: MonadIO m => IO a -> ReaderWriterIOT r w m a
liftIOR m = ReaderWriterIOT $ \x y -> liftIO m

liftR :: m a -> ReaderWriterIOT r w m a
liftR m = ReaderWriterIOT $ \x y -> m

fmapR :: Functor m => (a -> b) -> ReaderWriterIOT r w m a -> ReaderWriterIOT r w m b
fmapR f m = ReaderWriterIOT $ \x y -> fmap f (run m x y)

returnR :: Monad m => a -> ReaderWriterIOT r w m a
returnR a = ReaderWriterIOT $ \_ _ -> return a

bindR :: Monad m => ReaderWriterIOT r w m a -> (a -> ReaderWriterIOT r w m b) -> ReaderWriterIOT r w m b
bindR m k = ReaderWriterIOT $ \x y -> run m x y >>= \a -> run (k a) x y

mfixR :: MonadFix m => (a -> ReaderWriterIOT r w m a) -> ReaderWriterIOT r w m a
mfixR f = ReaderWriterIOT $ \x y -> mfix (\a -> run (f a) x y)

pureR :: Applicative m => a -> ReaderWriterIOT r w m a
pureR a = ReaderWriterIOT $ \_ _ -> pure a

apR :: Applicative m => ReaderWriterIOT r w m (a -> b) -> ReaderWriterIOT r w m a -> ReaderWriterIOT r w m b
apR f a = ReaderWriterIOT $ \x y -> run f x y <*> run a x y

readerWriterIOT :: (MonadIO m, Monoid w) =>
Expand Down
3 changes: 3 additions & 0 deletions reactive-banana/src/Reactive/Banana/Combinators.hs
Original file line number Diff line number Diff line change
Expand Up @@ -320,8 +320,11 @@ whenE bf = filterApply (const <$> bf)
split :: Event (Either a b) -> (Event a, Event b)
split e = (filterJust $ fromLeft <$> e, filterJust $ fromRight <$> e)
where
fromLeft :: Either a b -> Maybe a
fromLeft (Left a) = Just a
fromLeft (Right b) = Nothing

fromRight :: Either a b -> Maybe b
fromRight (Left a) = Nothing
fromRight (Right b) = Just b

Expand Down
34 changes: 26 additions & 8 deletions reactive-banana/src/Reactive/Banana/Internal/Combinators.hs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ compile setup = do
(output, s0) <- -- compile initial graph
Prim.compile (runReaderT setup eventNetwork) Prim.emptyNetwork
putMVar s s0 -- set initial state

return $ eventNetwork

fromAddHandler :: AddHandler a -> Moment (Event a)
Expand Down Expand Up @@ -112,22 +112,37 @@ imposeChanges = liftCached2 $ \(l1,_) p2 -> return (l1,p2)
{-----------------------------------------------------------------------------
Combinators - basic
------------------------------------------------------------------------------}
never = don'tCache $ liftBuild $ Prim.neverP
never :: Event a
never = don'tCache $ liftBuild $ Prim.neverP

unionWith :: (a -> a -> a) -> Event a -> Event a -> Event a
unionWith f = liftCached2 $ (liftBuild .) . Prim.unionWithP f

filterJust :: Event (Maybe a) -> Event a
filterJust = liftCached1 $ liftBuild . Prim.filterJustP
mapE f = liftCached1 $ liftBuild . Prim.mapP f
applyE = liftCached2 $ \(~(lf,_)) px -> liftBuild $ Prim.applyP lf px

changesB = liftCached1 $ \(~(lx,px)) -> liftBuild $ Prim.tagFuture lx px
mapE :: (a -> b) -> Event a -> Event b
mapE f = liftCached1 $ liftBuild . Prim.mapP f

applyE :: Behavior (a -> b) -> Event a -> Event b
applyE = liftCached2 $ \(~(lf,_)) px -> liftBuild $ Prim.applyP lf px

changesB :: Behavior a -> Event (Future a)
changesB = liftCached1 $ \(~(lx,px)) -> liftBuild $ Prim.tagFuture lx px

pureB :: a -> Behavior a
pureB a = cache $ do
p <- runCached never
return (Prim.pureL a, p)
applyB = liftCached2 $ \(~(l1,p1)) (~(l2,p2)) -> liftBuild $ do

applyB :: Behavior (a -> b) -> Behavior a -> Behavior b
applyB = liftCached2 $ \(~(l1,p1)) (~(l2,p2)) -> liftBuild $ do
p3 <- Prim.unionWithP const p1 p2
let l3 = Prim.applyL l1 l2
return (l3,p3)
mapB f = applyB (pureB f)

mapB :: (a -> b) -> Behavior a -> Behavior b
mapB f = applyB (pureB f)

{-----------------------------------------------------------------------------
Combinators - accumulation
Expand All @@ -147,6 +162,7 @@ cacheAndSchedule m = ask >>= \r -> liftBuild $ do
Prim.buildLater $ void $ runReaderT (runCached c) r
return c

stepperB :: a -> Event a -> Moment (Behavior a)
stepperB a e = cacheAndSchedule $ do
p0 <- runCached e
liftBuild $ do
Expand All @@ -155,6 +171,7 @@ stepperB a e = cacheAndSchedule $ do
(l,_) <- Prim.accumL a p1
return (l,p2)

accumE :: a -> Event (a -> a) -> Moment (Event a)
accumE a e1 = cacheAndSchedule $ do
p0 <- runCached e1
liftBuild $ do
Expand Down Expand Up @@ -184,7 +201,7 @@ executeP p1 = do
p2 <- Prim.mapP runReaderT p1
Prim.executeP p2 r

observeE :: Event (Moment a) -> Event a
observeE :: Event (Moment a) -> Event a
observeE = liftCached1 $ executeP

executeE :: Event (Moment a) -> Moment (Event a)
Expand Down Expand Up @@ -217,4 +234,5 @@ switchB b e = ask >>= \r -> cacheAndSchedule $ do
pr <- merge c1 =<< merge c2 c3
return (lr, pr)

merge :: Pulse () -> Pulse () -> Build (Pulse ())
merge = Prim.unionWithP (\_ _ -> ())
3 changes: 1 addition & 2 deletions reactive-banana/src/Reactive/Banana/Prim/Cached.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
module Reactive.Banana.Prim.Cached (
-- | Utility for executing monadic actions once
-- and then retrieving values from a cache.
--
--
-- Very useful for observable sharing.
Cached, runCached, cache, fromPure, don'tCache,
liftCached1, liftCached2,
Expand Down Expand Up @@ -63,4 +63,3 @@ liftCached2 f ca cb = cache $ do
a <- runCached ca
b <- runCached cb
f a b

15 changes: 9 additions & 6 deletions reactive-banana/src/Reactive/Banana/Prim/Combinators.hs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{-----------------------------------------------------------------------------
reactive-banana
------------------------------------------------------------------------------}
{-# LANGUAGE RecursiveDo #-}
{-# LANGUAGE RecursiveDo, ScopedTypeVariables #-}
module Reactive.Banana.Prim.Combinators where

import Control.Applicative
Expand All @@ -15,7 +15,7 @@ import Reactive.Banana.Prim.Plumbing
, readPulseP, readLatchP, readLatchFutureP, liftBuildP,
)
import qualified Reactive.Banana.Prim.Plumbing (pureL)
import Reactive.Banana.Prim.Types (Latch, Future, Pulse, Build)
import Reactive.Banana.Prim.Types (Latch, Future, Pulse, Build, EvalP)

import Debug.Trace
-- debug s = trace s
Expand Down Expand Up @@ -47,24 +47,26 @@ filterJustP p1 = do
p2 `dependOn` p1
return p2

unsafeMapIOP :: (a -> IO b) -> Pulse a -> Build (Pulse b)
unsafeMapIOP :: forall a b. (a -> IO b) -> Pulse a -> Build (Pulse b)
unsafeMapIOP f p1 = do
p2 <- newPulse "unsafeMapIOP" $
{-# SCC unsafeMapIOP #-} eval =<< readPulseP p1
p2 `dependOn` p1
return p2
where
eval :: Maybe a -> EvalP (Maybe b)
eval (Just x) = Just <$> liftIO (f x)
eval Nothing = return Nothing

unionWithP :: (a -> a -> a) -> Pulse a -> Pulse a -> Build (Pulse a)
unionWithP :: forall a. (a -> a -> a) -> Pulse a -> Pulse a -> Build (Pulse a)
unionWithP f px py = do
p <- newPulse "unionWithP" $
{-# SCC unionWithP #-} eval <$> readPulseP px <*> readPulseP py
p `dependOn` px
p `dependOn` py
return p
where
eval :: Maybe a -> Maybe a -> Maybe a
eval (Just x) (Just y) = Just (f x y)
eval (Just x) Nothing = Just x
eval Nothing (Just y) = Just y
Expand Down Expand Up @@ -111,12 +113,13 @@ switchL l pl = mdo
x <- stepperL l pl
return $ cachedLatch $ getValueL x >>= getValueL

executeP :: Pulse (b -> Build a) -> b -> Build (Pulse a)
executeP :: forall a b. Pulse (b -> Build a) -> b -> Build (Pulse a)
executeP p1 b = do
p2 <- newPulse "executeP" $ {-# SCC executeP #-} eval =<< readPulseP p1
p2 `dependOn` p1
return p2
where
eval :: Maybe (b -> Build a) -> EvalP (Maybe a)
eval (Just x) = Just <$> liftBuildP (x b)
eval Nothing = return Nothing

Expand All @@ -134,7 +137,7 @@ switchP pp = mdo
return Nothing
-- fetch value from old parent
eval = readPulseP =<< readLatchP lp

p1 <- newPulse "switchP_in" switch :: Build (Pulse ())
p1 `dependOn` pp
p2 <- newPulse "switchP_out" eval
Expand Down
13 changes: 6 additions & 7 deletions reactive-banana/src/Reactive/Banana/Prim/Compile.hs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import Reactive.Banana.Prim.Types
{-----------------------------------------------------------------------------
Compilation
------------------------------------------------------------------------------}
-- | Change a 'Network' of pulses and latches by
-- | Change a 'Network' of pulses and latches by
-- executing a 'BuildIO' action.
compile :: BuildIO a -> Network -> IO (a, Network)
compile m state1 = do
Expand Down Expand Up @@ -59,7 +59,7 @@ interpret f xs = do
pout <- liftBuild $ mapP return pmid
liftBuild $ addHandler pout (writeIORef o . Just)
return sin

-- compile initial network
(sin, state) <- compile network emptyNetwork

Expand All @@ -70,13 +70,13 @@ interpret f xs = do
ma <- readIORef o -- read output
writeIORef o Nothing
return (ma,s2)

mapAccumM go state xs -- run several steps

-- | Execute an FRP network with a sequence of inputs.
-- Make sure that outputs are evaluated, but don't display their values.
--
-- Mainly useful for testing whether there are space leaks.
--
-- Mainly useful for testing whether there are space leaks.
runSpaceProfile :: Show b => (Pulse a -> BuildIO (Pulse b)) -> [a] -> IO ()
runSpaceProfile f xs = do
let g = do
Expand All @@ -91,7 +91,7 @@ runSpaceProfile f xs = do
(outputs, s2) <- step x s1
outputs -- don't forget to execute outputs
return ((), s2)

mapAccumM_ fire network xs

-- | 'mapAccum' for a monad.
Expand All @@ -108,4 +108,3 @@ mapAccumM_ _ _ [] = return ()
mapAccumM_ f !s0 (x:xs) = do
(_,s1) <- f x s0
mapAccumM_ f s1 xs

1 change: 1 addition & 0 deletions reactive-banana/src/Reactive/Banana/Prim/Dependencies.hs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ buildDependencies (Endo f, parents) = do
sequence_ [x `doAddChild` y | x <- Graph.listParents gr, y <- Graph.getChildren gr x]
sequence_ [x `doChangeParent` y | (P x, P y) <- parents]
where
gr :: Graph.Graph SomeNode
gr = f Graph.emptyGraph

{-----------------------------------------------------------------------------
Expand Down
Loading

0 comments on commit a60e40b

Please sign in to comment.