module Control.FRPNow.Core(
Event,Behavior, never, switch, whenJust, futuristic,
Now, async, asyncOS, callback, sampleNow, planNow, sync,
runNowMaster,
initNow) where
import Control.Concurrent.Chan
import Control.Exception
import Data.Typeable
import Control.Applicative hiding (empty,Const)
import Control.Monad hiding (mapM_)
import Control.Monad.IO.Class
import Control.Monad.Reader hiding (mapM_)
import Control.Monad.Writer hiding (mapM_)
import Data.IORef
import Control.FRPNow.Private.Ref
import Control.FRPNow.Private.PrimEv
import System.IO.Unsafe
import Debug.Trace
import Prelude
data Event a
= Never
| Occ a
| E (M (Event a))
newtype EInternal a = EInternal { runEInternal :: M (Either (EInternal a) (Event a)) }
data State = Update
| Redirect
runE :: Event a -> M (Event a)
runE Never = return Never
runE (Occ x) = return (Occ x)
runE (E m) = m
instance Monad Event where
return = Occ
Never >>= _ = Never
(Occ x) >>= f = f x
(E m) >>= f = memoE $ bindInternal m f
never :: Event a
never = Never
setE :: a -> Event x -> Event a
setE _ Never = Never
setE a (Occ _) = Occ a
setE a (E m) = E $ setE a <$> m
bindInternal :: M (Event a) -> (a -> Event b) -> EInternal b
m `bindInternal` f = EInternal $
m >>= \r -> case r of
Never -> return (Right Never)
Occ x -> Right <$> runE (f x)
E m' -> return (Left $ m' `bindInternal` f)
minTime Never r = setE () r
minTime l Never = setE () l
minTime (Occ _) _ = Occ ()
minTime _ (Occ _) = Occ ()
minTime (E ml) (E mr) = memoE $ minInternal ml mr
minInternal :: M (Event a) -> M (Event b) -> EInternal ()
minInternal ml mr = EInternal $
do er <- mr
case er of
Occ x -> return (Right (Occ ()))
Never -> return (Right (setE () $ E ml))
E mr' -> do el <- ml
return $ case el of
Occ x -> Right (Occ ())
Never -> Right (setE () $ E mr')
E ml' -> Left (minInternal ml' mr')
memoEIO :: EInternal a -> IO (Event a)
memoEIO einit =
do r <- newIORef (Left einit,Nothing )
return (usePrevE r)
usePrevE :: IORef (Either (EInternal a) (Event a), (Maybe (Round, Event a))) -> Event a
usePrevE r = self where
self = E $
do (s,cached) <- liftIO (readIORef r)
round <- getRound
case cached of
Just (cr,cache) | cr == round -> return cache
_ -> case s of
Left ei -> do ri <- runEInternal ei
case ri of
Left _ -> do liftIO (writeIORef r (ri,Just (round,self) ) )
return self
Right e -> do liftIO (writeIORef r (ri, Just (round,e)) )
return e
Right e -> do e' <- runE e
liftIO (writeIORef r (Right e', Just (round,e')))
return e'
memoE :: EInternal a -> Event a
memoE e = unsafePerformIO $ memoEIO e
data Behavior a = B (M (a, Event (Behavior a)))
| Const a
data BInternal a = BInternal { runBInternal :: M (Either (BInternal a, a, Event ()) (Behavior a)) }
memoBIIO :: BInternal a -> IO (Behavior a)
memoBIIO einit =
do r <- newIORef (Left einit, Nothing)
return (usePrevBI r)
usePrevBI :: IORef (Either (BInternal a) (Behavior a), Maybe (a, Event (Behavior a)) ) -> Behavior a
usePrevBI r = self where
self = B $
do (s,cached) <- liftIO (readIORef r)
case cached of
Just (cache@(i,ev)) ->
do ev' <- runE ev
case ev' of
Occ x -> update s
_ -> do liftIO (writeIORef r (s, Just (i,ev')))
return (i,ev')
Nothing -> update s
update s = case s of
Left ei -> do ri <- runBInternal ei
case ri of
Left (bi',i,e) ->
do let res = (i, setE self e)
liftIO (writeIORef r (Left bi',Just res))
return res
Right b -> do res@(h,t) <- runB b
liftIO (writeIORef r (Right (rerunBh res), Just res))
return res
Right b -> do res@(h,t) <- runB b
liftIO (writeIORef r (Right (rerunBh res), Just res))
return res
memoBInt :: BInternal a -> Behavior a
memoBInt e = unsafePerformIO $ memoBIIO e
runB :: Behavior a -> M (a, Event (Behavior a))
runB (B m) = m
runB (Const a) = return (a, never)
rerunBh :: (a,Event(Behavior a)) -> Behavior a
rerunBh (h,Never) = Const h
rerunBh (h,t) = B $ runE t >>= \x -> case x of
Occ b -> runB b
t' -> return (h,t')
rerunB :: a -> Event (Behavior a) -> M (a, Event (Behavior a))
rerunB h Never = return (h, Never)
rerunB h t = runE t >>= \x -> case x of
Occ b -> runB b
t' -> return (h,t')
switchInternal :: M (a, Event (Behavior a)) -> M (Event (Behavior a)) -> BInternal a
switchInternal mb me = BInternal $
do e <- me
case e of
Occ x -> return (Right x)
Never -> return (Right (B mb))
E me' -> do (i,ei) <- mb
return $ Left (switchInternal (rerunB i ei) me', i, minTime ei e)
stepInternal :: a -> M (Event (Behavior a)) -> BInternal a
stepInternal i me =BInternal $
do e <- me
return $ case e of
Occ x -> Right x
Never -> Right (Const i)
E me' -> Left (stepInternal i me', i, setE () e)
bindBInternal :: M (a,Event (Behavior a)) -> (a -> Behavior b) -> BInternal b
bindBInternal m f =
BInternal $
do (h,t) <- m
case t of
Never -> return $ Right (f h)
Occ _ -> error "invariant broken"
_ ->
case f h of
Const x -> return $ Left (bindBInternal (rerunB h t) f, x, setE () t)
B n -> do (hn,tn) <- n
return $ Left (bindBInternal (rerunB h t) f, hn, minTime t tn)
bindB :: Behavior a -> (a -> Behavior b) -> Behavior b
bindB (Const x) f = f x
bindB (B m) f = memoBInt $ bindBInternal m f
whenJustInternal :: M (Maybe a, Event (Behavior (Maybe a))) -> Behavior (Event a) -> BInternal (Event a)
whenJustInternal m outerSelf = BInternal $
do (h, t) <- m
case t of
Never -> return $ Right $ pure $ case h of
Just x -> pure x
Nothing -> never
Occ _ -> error "invariant broken"
_ ->
case h of
Just x -> return $ Left (whenJustInternal (rerunB h t) outerSelf, return x, setE () t)
Nothing ->
do en <- planM (setE (runB outerSelf) t)
return $ Left (whenJustInternal (rerunB h t) outerSelf, en >>= fst, setE () t)
whenJust' :: Behavior (Maybe a) -> Behavior (Event a)
whenJust' (Const Nothing) = pure never
whenJust' (Const (Just x)) = pure (pure x)
whenJust' (B m) = let x = memoBInt $ whenJustInternal m x
in x
instance Monad Behavior where
return x = B $ return (x, never)
m >>= f = m `bindB` f
instance MonadFix Behavior where
mfix f = B $ mfix $ \(~(h,_)) ->
do (h',t) <- runB (f h)
return (h', mfix f <$ t )
switch :: Behavior a -> Event (Behavior a) -> Behavior a
switch b Never = b
switch _ (Occ b) = b
switch (Const x) (E em) = memoBInt (stepInternal x em)
switch (B bm) (E em) = memoBInt (switchInternal bm em)
whenJust :: Behavior (Maybe a) -> Behavior (Event a)
whenJust b = (whenJust' b)
futuristic :: Behavior (Event a) -> Behavior (Event a)
futuristic b = B $ do e <- makeLazy $ fst <$> runB b
return (e,futuristic b <$ e)
unrunB :: (a,Event (Behavior a)) -> Behavior a
unrunB (h, Never) = Const h
unrunB (h,t) = B $
runE t >>= \x -> case x of
Occ b -> runB b
t' -> return (h,t')
data Env = Env {
plansRef :: IORef Plans,
laziesRef :: IORef Lazies,
clock :: Clock }
type M = ReaderT Env IO
newtype Now a = Now { getNow :: M a } deriving (Functor,Applicative,Monad, MonadFix, MonadIO)
sampleNow :: Behavior a -> Now a
sampleNow (B m) = Now $ fst <$> m
callback :: Now (Event a, a -> IO ())
callback = Now $ do c <- clock <$> ask
(pe, cb) <- liftIO $ callbackp c
return (toE pe,cb)
sync :: IO a -> Now a
sync m = Now $ liftIO m
async :: IO a -> Now (Event a)
async m = Now $ do c <- clock <$> ask
toE <$> liftIO (spawn c m)
asyncOS :: IO a -> Now (Event a)
asyncOS m = Now $ do c <- clock <$> ask
toE <$> liftIO (spawnOS c m)
toE :: PrimEv a -> Event a
toE p = E toEM where
toEM = (toEither . (p `observeAt`) <$> getRound)
toEither Nothing = E toEM
toEither (Just x) = Occ x
getRound :: M Round
getRound = ReaderT $ \env -> curRound (clock env)
type Plan a = IORef (Either (Event (M a)) a)
planToEv :: Plan a -> Event a
planToEv ref = self where
self = E $
liftIO (readIORef ref) >>= \pstate ->
case pstate of
Right x -> return (Occ x)
Left ev -> runE ev >>= \estate ->
case estate of
Occ m -> do x <- m
liftIO $ writeIORef ref (Right x)
return $ Occ x
ev' -> do liftIO $ writeIORef ref (Left ev')
return self
data SomePlan = forall a. SomePlan (Ref (Plan a))
type Plans = [SomePlan]
type Lazies = [Lazy]
data Lazy = forall a. Lazy (M (Event a)) (IORef (Event a))
makeLazy :: M (Event a) -> M (Event a)
makeLazy m = ReaderT $ \env ->
do n <- curRound (clock env)
r <- newIORef (error "should not have read lazy yet")
modifyIORef (laziesRef env) (Lazy m r :)
return (readLazyState n r)
readLazyState :: Round -> IORef (Event a) -> Event a
readLazyState n r =
let x = E $
do m <- getRound
case compare n m of
LT -> liftIO (readIORef r) >>= runE
EQ -> return x
GT -> error "Round seems to decrease.."
in x
planM :: Event (M a) -> M (Event a)
planM e = plan makeWeakIORef e
planNow :: Event (Now a) -> Now (Event a)
planNow e = Now $
do e' <- runE e
case e' of
Occ x -> pure <$> getNow x
Never -> return Never
_ -> plan makeStrongRef (getNow <$> e)
plan :: (forall v. IORef v -> IO (Ref (IORef v))) -> Event (M a) -> M (Event a)
plan makeRef e =
do p <- liftIO (newIORef $ Left e)
let ev = planToEv p
pr <- liftIO (makeRef p)
addPlan pr
return ev
addPlan :: Ref (Plan a) -> M ()
addPlan p = ReaderT $ \env -> modifyIORef (plansRef env) (SomePlan p :)
initNow ::
(IO (Maybe a) -> IO ())
-> Now (Event a)
-> IO ()
initNow schedule (Now m) =
mdo c <- newClock (schedule it)
pr <- newIORef []
lr <- newIORef []
let env = Env pr lr c
let it = runReaderT (iteration e) env
e <- runReaderT m env
runReaderT (iterationMeat e) env
return ()
iteration :: Event a -> M (Maybe a)
iteration ev =
newRoundM >>= \new ->
if new
then iterationMeat ev
else return Nothing
iterationMeat ev =
do er <- runE ev
case er of
Occ x -> return (Just x)
_ -> tryPlans >> runLazies >> return Nothing
newRoundM :: M Bool
newRoundM = ReaderT $ \env -> newRound (clock env)
tryPlans :: M ()
tryPlans = ReaderT $ tryEm where
tryEm env =
do pl <- readIORef (plansRef env)
writeIORef (plansRef env) []
runReaderT (mapM_ tryPlan (reverse pl)) env
tryPlan (SomePlan pr) =
do
ps <- liftIO (deRef pr)
case ps of
Just p -> do eres <- runE (planToEv p)
case eres of
Occ x -> return ()
_ -> addPlan pr
Nothing -> return ()
runLazies :: M ()
runLazies = ReaderT $ runEm where
runEm env =
readIORef (laziesRef env) >>= \pl ->
if null pl
then return ()
else do writeIORef (laziesRef env) []
runReaderT (mapM_ runLazy (reverse pl)) env
runEm env where
runLazy (Lazy m r) = do e <- m
x <- runE e
case x of
Occ _ -> error "Forced lazy was not lazy!"
e' -> liftIO $ writeIORef r e'
data FRPWaitsForNeverException = FRPWaitsForNeverException deriving (Show, Typeable)
instance Exception FRPWaitsForNeverException
runNowMaster :: Now (Event a) -> IO a
runNowMaster m =
do chan <- newChan
let enqueue m = writeChan chan m
initNow enqueue m
loop chan where
loop chan =
do m <- catch (readChan chan)
(\e -> do let err = (e :: BlockedIndefinitelyOnMVar)
throw FRPWaitsForNeverException)
mr <- m
case mr of
Just x -> return x
Nothing -> loop chan
instance Functor Behavior where
fmap = liftM
instance Applicative Behavior where
pure = return
(<*>) = ap
instance Functor Event where
fmap = liftM
instance Applicative Event where
pure = return
(<*>) = ap