Journal entry for


I’ll debug my weak references later. Now I’m feeling like exploring an idea I’ve had which I’m not sure I’ve written about before.

“Timeline transformer” EventWriter

It’s a more effect-y version of Reflex’ EventWriter, with types looking something like:

runEventWriter ::
  forall s
  . Semigroup w
  =>((forall x a. Lowerable ET x => x (ET w s t) a -> x t a)
    -> Now (ET w s t) b)
  -> Now t (b, Event

tellE :: Semigroup w => Event (ET w s t) w -> Now (ET w s t) ()

liftETE :: Event t a -> Event (ET w s t) a
liftETB :: Behavior t a -> Behavior (ET w s t) a

class Lowerable f x where
  lower :: Frp t => x (f t) a -> x t a

This uses the StT phantom type (?) technique to make sure the effect doesn’t leak.

It has the advantage that you can keep doing normal FRP programming without having to use functions like those from Reflex’ Adjustable class which pollute everything with a wrapper type:

class (Reflex t, Monad m) => Adjustable t m | m -> t where
  runWithReplace
    :: m a
    -> Event t (m b)
    -> m (a, Event t b)

If I manage to implement this correctly then I think it also has a very efficient imperative implementation.

On the other hand I’m not 100% sure on what a pure implementation looks like exactly. But, I think figuring that out would lead to some great insights, and possibly a path from pure implementation to imperative implementation via simple reasoning. The same would apply to my distributed FRP work.

I think the hard part is coming up with identifiers for every event that is added; an event could be “added” many times in a pure implementation but this should have no effect on the output event. If I can uniquely identify each event then that’s no problem.

On second thought: this seems like a fool’s errand, because I could only “tell” from Nows which are used in the end result. The only reason

sampleNow :: Event (Now a) -> Event a

works out is because it’s semantically a reader monad.

I think this means that you cannot implement it without having access to the program definition in your semantics.

The meaning of the clean EventWriter would then be something like “the merge of all events being the subject of a tell in the source, starting from the “execution” of runEventWriter”. That means you’d need to define what “execution” means here.

I think I’ll just write a “reader timeline transformer” first.