This is a question about Jane Street’s Incremental library.
I am trying to do this: I want to register future events using
step_function, and then advance time to a future time when possibly several alarms have already passed. Then I would like to trigger all of the alarms that have passed, in order (up to the configured precision) and fold over them. To be concrete, let’s say I want to get a new
Incremental.S.t which accumulates in a list all the times at which alarms have fired up to the current time.
I suspect this is not possible in Incremental? I did find functions to trigger all past alarms in Core_kernel.Timing_wheel but nothing is exposed in Incremental.
Such operations are fundamentally at odds with the dynamism of Incremental. Any given value might become available and then unavailable as the graph dynamically changes, so you can’t write history dependent computations in an uncontrolled way without creating space leaks. This is fundamentally the same problem that monadic FRP bumps up against.
You should think of Incremental as a system for optimizing a pure function over some set of input values. Don’t look to Incremental for new semantics, just performance. If you want a pure function that depends on the history of your system, you need to explicitly capture that history and place it in to your input data. You should do the same when building an incremental computation.
You can capture the history of some incrementals by observing them, and writing down some derivate of the history in other variables, and then calling stabilize again. This is morally the same as calling a pure function on your input data, and then adding the result of that computation to your input data.
And to answer your more precise question, you can achieve what you want by writing an Async program that samples your incremental computation.
Ok, thanks. That’s a helpful way of thinking about it. I guess I could maintain a separate timing wheel explicitly, advancing time and processing alarms in it which then feed an Incremental computational graph downstream.
You might want to look at Async_kernel.Synchronous_time_source for this purpose.
Thanks. Actually I oversimplified a bit. What I want is a system with feedback (for an even-driven simulation). So, one alarm will trigger computations (managed by Incremental) which then have the effect of rescheduling some future alarms. For this to work I would need a way to process alarms strictly one at a time. I’m not sure if that’s doable with Timing_wheel, when more than one alarm fall in the same time bin. It seems one only has the option to process all alarms one after the other without interruption. That would be fine without feedback on the scheduler itself, but I think modifying the Timing_wheel during processing due to feedback would be unsound?
I believe you can call Event.at or Event.after from within a callback, if that’s what you’re asking.