
So this is a bit of a brainstorming post. I did a little thinking earlier about different simple ODE solving techniques, and tried to translate them fairly directly into Reactive. The result isn't pretty & I'd like to talk about that. The naive definitions, to me, of the Euler, Euler-Cromer, and Midpoint methods should look like the following. Each takes in an Event (), initial positions & velocities, and a Behavior (v -> v -> v) that is the acceleration as a function of time. We want to be general since the acceleration may be an explicit function of time as well as as position & velocity. euler tau x0 v0 a = liftA2 (,) x v where x = accumB x0 (fmap (^+^) (liftA2 (^*) (prev vi) deltaTs)) v = accumB v0 (fmap (^+^) (liftA2 (^*) ai deltaTs)) ai = (snapshot_ tau a) <*> (prev xi) <*> (prev vi) xi = (snapshot_ tau x) vi = (snapshot_ tau v) deltaTs = diffE (tau `snapshot_` time) eulerCromer tau x0 v0 a = liftA2 (,) x v where x = accumB x0 (fmap (^+^) (liftA2 (^*) vi deltaTs)) v = accumB v0 (fmap (^+^) (liftA2 (^*) ai deltaTs)) ai = (snapshot_ tau a) <*> (prev xi) <*> (prev vi) xi = snapshot_ tau x vi = snapshot_ tau v deltaTs = diffE (tau `snapshot_` time) midpoint tau x0 v0 a = liftA2 (,) x v where x = accumB x0 (fmap (^+^) (liftA2 (^*) vavg deltaTs)) v = accumB v0 (fmap (^+^) (liftA2 (^*) ai deltaTs)) ai = (snapshot_ tau a) <*> (prev xi) <*> (prev vi) xi = snapshot_ tau x vi = snapshot_ tau v deltaTs = diffE (tau `snapshot_` time) vavg = fmap (^/2) $ liftA2 (^+^) vi (prev vi) prev :: Event a -> Event a prev = fmap snd . withPrevE this code is fairly verbose, but that's because I'm trying to be very explicit about the ordering of the sampling & how the new values at each time step are created. The problem is that I feel like I'm wrestling very hard against Reactive rather than working with it. I was hoping that I could get some feedback on a way to write these very simple algorithms that is more inline with the spirit of the API.