Journal entry for
I’ve continued working on understanding how Reflex works and trying to implement FRP using an occurs :: Event a -> m (Maybe a)
implementation primitive.
Such a primitive might help with making a reasonably efficiont implementation which doesn’t rely on many event merge primitives such as mergeIncrementalG
and mergeIncrementalWithMoveG
from Reflex (mergeCheapWithMove
, mergeCheap
, and mergeIntCheap
in the implementation).
It might also make coincidence
and functions like push
in Reflex share code.
I’m doing this on two fronts: one is my simple FRP implementation, for which I copied part of Reflex’ test suite, and the other is working on Reflex’ Spider implementation.
While looking at the latter I discovered some duplicated code between coincidence
and switch
which I factored out.
Now I’m looking at the various merge
functions and trying to see what they share.
For the simple implementation I’ve been copying code from Reflex.Spider
but I haven’t yet made my tests run with this implementation (before I had a different one which passed all the tests but wasn’t lazy enough to express some definitions without looping).
Getting the tests to run is my priority now.
I’ll also grab a local copy of Reflex and apply my refactorings there so I can run the official test suite and be more confident that I haven’t messed up.
For future reference, here’s a pure implementation of my simple FRP library using occurs
where I could:
instance (Enum t, Ord t) => Frp (Pure t) where
newtype Event (Pure t) a = Event { unEvent :: t -> Maybe a }
newtype Behavior (Pure t) a = Behavior { unBehavior :: t -> a }
deriving (Functor, Applicative, Monad) via (->) t
type Now (Pure t) = (->) t
sample = unBehavior
never = toEvent $ pure Nothing
sampleAtMaybe f = toEvent . runMaybeT . (MaybeT . f <=< MaybeT . occurs)
coincidence = Frp.sampleAtMaybe occurs
hold a e'@(Event e) fromT = Behavior $ \sampleT -> do
if sampleT <= fromT
then a
else case e (pred sampleT) of
Nothing -> unBehavior (hold a e' fromT) (pred sampleT)
Just a' -> a'
now = Event . (\t' -> guard . (t' ==))
mergeE a b = toEvent $ align <$> occurs a <*> occurs b
switch = toEvent . (occurs <=< Frp.sample)
occurs :: Event (Pure t) a -> Now (Pure t) (Maybe a)
occurs = unEvent
toEvent :: Now (Pure t) (Maybe a) -> Event (Pure t) a
toEvent = Event
nonEmpty :: Foldable t => t a -> Maybe (t a)
nonEmpty xs = if null xs then Nothing else Just xs
mergeIntMap :: (Witherable f, Foldable f) => f (Event (Pure t) a) -> Event (Pure t) (f a)
mergeIntMap =
toEvent . fmap nonEmpty . wither occurs