{-# LANGUAGE CPP #-}
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE PolyKinds #-}
#ifdef USE_REFLEX_OPTIMIZER
{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
#endif
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Reflex.Pure
( Pure
, Behavior (..)
, Event (..)
, Dynamic (..)
, Incremental (..)
) where
import Control.Monad
import Data.Dependent.Map (DMap)
import Data.GADT.Compare (GCompare)
import qualified Data.Dependent.Map as DMap
import Data.IntMap (IntMap)
import qualified Data.IntMap as IntMap
import Data.Maybe
import Data.MemoTrie
import Data.Monoid
import Data.Type.Coercion
import Reflex.Class
import Data.Kind (Type)
data Pure (t :: Type)
instance (Enum t, HasTrie t, Ord t) => Reflex (Pure t) where
newtype Behavior (Pure t) a = Behavior { unBehavior :: t -> a }
newtype Event (Pure t) a = Event { unEvent :: t -> Maybe a }
newtype Dynamic (Pure t) a = Dynamic { unDynamic :: t -> (a, Maybe a) }
newtype Incremental (Pure t) p = Incremental { unIncremental :: t -> (PatchTarget p, Maybe p) }
type PushM (Pure t) = (->) t
type PullM (Pure t) = (->) t
never :: Event (Pure t) a
never = Event $ \_ -> Nothing
constant :: a -> Behavior (Pure t) a
constant x = Behavior $ \_ -> x
push :: (a -> PushM (Pure t) (Maybe b)) -> Event (Pure t) a -> Event (Pure t) b
push f e = Event $ memo $ \t -> unEvent e t >>= \o -> f o t
pushCheap :: (a -> PushM (Pure t) (Maybe b)) -> Event (Pure t) a -> Event (Pure t) b
pushCheap = push
pull :: PullM (Pure t) a -> Behavior (Pure t) a
pull = Behavior . memo
mergeG nt events = Event $ memo $ \t ->
let currentOccurrences = DMap.mapMaybeWithKey (\_ q -> case nt q of Event a -> a t) events
in if DMap.null currentOccurrences
then Nothing
else Just currentOccurrences
fanG e = EventSelectorG $ \k -> Event $ \t -> unEvent e t >>= DMap.lookup k
switch :: Behavior (Pure t) (Event (Pure t) a) -> Event (Pure t) a
switch b = Event $ memo $ \t -> unEvent (unBehavior b t) t
coincidence :: Event (Pure t) (Event (Pure t) a) -> Event (Pure t) a
coincidence e = Event $ memo $ \t -> unEvent e t >>= \o -> unEvent o t
current :: Dynamic (Pure t) a -> Behavior (Pure t) a
current d = Behavior $ \t -> fst $ unDynamic d t
updated :: Dynamic (Pure t) a -> Event (Pure t) a
updated d = Event $ \t -> snd $ unDynamic d t
unsafeBuildDynamic :: PullM (Pure t) a -> Event (Pure t) a -> Dynamic (Pure t) a
unsafeBuildDynamic readV0 v' = Dynamic $ \t -> (readV0 t, unEvent v' t)
unsafeBuildIncremental readV0 p = Incremental $ \t -> (readV0 t, unEvent p t)
mergeIncrementalG = mergeIncrementalImpl
mergeIncrementalWithMoveG = mergeIncrementalImpl
currentIncremental i = Behavior $ \t -> fst $ unIncremental i t
updatedIncremental i = Event $ \t -> snd $ unIncremental i t
incrementalToDynamic i = Dynamic $ \t ->
let (old, mPatch) = unIncremental i t
e = case mPatch of
Nothing -> Nothing
Just patch -> apply patch old
in (old, e)
behaviorCoercion Coercion = Coercion
eventCoercion Coercion = Coercion
dynamicCoercion Coercion = Coercion
incrementalCoercion Coercion Coercion = Coercion
fanInt e = EventSelectorInt $ \k -> Event $ \t -> unEvent e t >>= IntMap.lookup k
mergeIntIncremental = mergeIntIncrementalImpl
mergeIncrementalImpl :: (PatchTarget p ~ DMap k q, GCompare k)
=> (forall a. q a -> Event (Pure t) (v a))
-> Incremental (Pure t) p -> Event (Pure t) (DMap k v)
mergeIncrementalImpl nt i = Event $ \t ->
let results = DMap.mapMaybeWithKey (\_ q -> case nt q of Event e -> e t) $ fst $ unIncremental i t
in if DMap.null results
then Nothing
else Just results
mergeIntIncrementalImpl :: (PatchTarget p ~ IntMap (Event (Pure t) a)) => Incremental (Pure t) p -> Event (Pure t) (IntMap a)
mergeIntIncrementalImpl i = Event $ \t ->
let results = IntMap.mapMaybeWithKey (\_ (Event e) -> e t) $ fst $ unIncremental i t
in if IntMap.null results
then Nothing
else Just results
instance Functor (Dynamic (Pure t)) where
fmap f d = Dynamic $ \t -> let (cur, upd) = unDynamic d t
in (f cur, fmap f upd)
instance Applicative (Dynamic (Pure t)) where
pure a = Dynamic $ \_ -> (a, Nothing)
(<*>) = ap
instance Monad (Dynamic (Pure t)) where
return = pure
(x :: Dynamic (Pure t) a) >>= (f :: a -> Dynamic (Pure t) b) = Dynamic $ \t ->
let (curX :: a, updX :: Maybe a) = unDynamic x t
(cur :: b, updOuter :: Maybe b) = unDynamic (f curX) t
(updInner :: Maybe b, updBoth :: Maybe b) = case updX of
Nothing -> (Nothing, Nothing)
Just nextX -> let (c, u) = unDynamic (f nextX) t
in (Just c, u)
in (cur, getFirst $ mconcat $ map First [updBoth, updOuter, updInner])
instance MonadSample (Pure t) ((->) t) where
sample :: Behavior (Pure t) a -> (t -> a)
sample = unBehavior
instance (Enum t, HasTrie t, Ord t) => MonadHold (Pure t) ((->) t) where
hold :: a -> Event (Pure t) a -> t -> Behavior (Pure t) a
hold initialValue e initialTime = Behavior f
where f = memo $ \sampleTime ->
if sampleTime <= initialTime
then initialValue
else let lastTime = pred sampleTime
in fromMaybe (f lastTime) $ unEvent e lastTime
holdDyn v0 = buildDynamic (return v0)
buildDynamic :: (t -> a) -> Event (Pure t) a -> t -> Dynamic (Pure t) a
buildDynamic initialValue e initialTime =
let Behavior f = hold (initialValue initialTime) e initialTime
in Dynamic $ \t -> (f t, unEvent e t)
holdIncremental :: Patch p => PatchTarget p -> Event (Pure t) p -> t -> Incremental (Pure t) p
holdIncremental initialValue e initialTime = Incremental $ \t -> (f t, unEvent e t)
where f = memo $ \sampleTime ->
if sampleTime <= initialTime
then initialValue
else let lastTime = pred sampleTime
lastValue = f lastTime
in case unEvent e lastTime of
Nothing -> lastValue
Just x -> fromMaybe lastValue $ apply x lastValue
headE = slowHeadE
now t = Event $ guard . (t ==)