Idiomatic, purely-functional discrete event simulation and much more.
See README first in order to make sense of all this. It provides definitions and rationale for concepts.
e-XXX
functionsArities for e-XXX
functions follow the same convention. Providing both ranks
and path
refers explicitely
to a prioritized location in the event tree. Without path
, the path of the currently executing flat event is
retrieved (ie. acts with the given ranks
relative to the current path
). Not providing either refers explicitely
to the current flat event and its working queue.
Idiomatic, purely-functional discrete event simulation and much more. See README first in order to make sense of all this. It provides definitions and rationale for concepts. Arity convention for `e-XXX` functions ====================================== Arities for `e-XXX` functions follow the same convention. Providing both `ranks` and `path` refers explicitely to a prioritized location in the event tree. Without `path`, the path of the currently executing flat event is retrieved (ie. acts with the given `ranks` relative to the current `path`). Not providing either refers explicitely to the current flat event and its working queue.
(basic-engine)
Returns a function ctx -> ctx
which pops the next ranked events and executes them.
If the said ctx
does not have any event, returns nil.
Returns a function `ctx -> ctx` which pops the next ranked events and executes them. If the said `ctx` does not have any event, returns nil.
(e-assoc ctx event)
(e-assoc ctx ranks event)
(e-assoc ctx ranks path event)
Schedules an event
.
Follows arity convention presented in the namespace description.
Arity | Means |
---|---|
2 | Replaces the current working queue with the given event . |
3 | Schedules the event in the event tree for the given ranks and path returned by path . |
4 | Full control of when and where in the event tree. |
It is bad practice to associate something such as an empty queue. It means that "nothing" is unnecessarily scheduled.
Schedules an `event`. Follows arity convention presented in the namespace description. | Arity | Means | |---|---| | 2 | Replaces the current working queue with the given `event`. | | 3 | Schedules the `event` in the event tree for the given `ranks` and path returned by [[path]]. | | 4 | Full control of when and where in the event tree. | It is bad practice to associate something such as an empty queue. It means that "nothing" is unnecessarily scheduled.
(e-conj ctx event)
(e-conj ctx ranks event)
(e-conj ctx ranks path event)
Enqueues an event
, creating a queue if there is none.
Follows arity convention presented in the namespace description (see also e-assoc
).
It is bad practice to conj something such as an empty queue. It means that "nothing" is unnecessarily scheduled.
Enqueues an `event`, creating a queue if there is none. Follows arity convention presented in the namespace description (see also [[e-assoc]]). It is bad practice to conj something such as an empty queue. It means that "nothing" is unnecessarily scheduled.
(e-dissoc ctx)
(e-dissoc ctx ranks)
(e-dissoc ctx ranks path)
Cancels a scheduled event.
Follows arity convention presented in the namespace description.
Arity | Means |
---|---|
1 | Removes the currently executing flat event. |
2 | In the event tree, removes the event located at ranks relative to the current path. |
3 | In the event tree, remove the event located at ranks and path . |
Cancels a scheduled event. Follows arity convention presented in the namespace description. | Arity | Means | |---|---| | 1 | Removes the currently executing flat event. | | 2 | In the event tree, removes the event located at `ranks` relative to the current path. | | 3 | In the event tree, remove the event located at `ranks` and `path`. |
(e-get ctx)
(e-get ctx ranks path)
(e-get ctx ranks path not-found)
Retrieves a scheduled event.
Follows arity convention presented in the namespace description.
Arity | Means |
---|---|
1 | Returns the current working queue. |
3 | Returns the event located path and prioritized by ranks in the event tree. |
4 | As above, but returns not-found is instead of nil when there is no event. |
Retrieves a scheduled event. Follows arity convention presented in the namespace description. | Arity | Means | |---|---| | 1 | Returns the current working queue. | | 3 | Returns the event located `path` and prioritized by `ranks` in the event tree. | | 4 | As above, but returns `not-found` is instead of nil when there is no event. |
(e-into ctx events)
(e-into ctx ranks events)
(e-into ctx ranks path events)
Like e-conj
, but for a collection of events
.
Follows arity convention presented in the namespace description (see also e-assoc
).
Metadata of the given collection is merged with the already existing queue if there is one.
It is bad practice to add empty events. A queue will be scheduled for nothing.
Like [[e-conj]], but for a collection of `events`. Follows arity convention presented in the namespace description (see also [[e-assoc]]). Metadata of the given collection is merged with the already existing queue if there is one. It is bad practice to add empty events. A queue will be scheduled for nothing.
(e-isolate ctx)
(e-isolate ctx ranks)
(e-isolate ctx ranks path)
Isolating means that the current working queue or the requested queue in the event tree will be nested in an outer queue.
Follows arity convention presented in the namespace description.
Isolating means that the current working queue or the requested queue in the event tree will be nested in an outer queue. Follows arity convention presented in the namespace description.
(e-push ctx q)
(e-push ctx ranks q)
(e-push ctx ranks path q)
Similar to e-into
but works the other way around. Already scheduled events are added to the given
queue q
and their metadata data is merged.
Follows arity convention presented in the namespace description.
Similar to [[e-into]] but works the other way around. Already scheduled events are added to the given queue `q` and their metadata data is merged. Follows arity convention presented in the namespace description.
(e-update ctx f)
(e-update ctx ranks f)
(e-update ctx ranks path f)
Seldom used by the user, often used by other e-XXX
functions.
Follows arity convention presented in the namespace description.
Works like standard update
but tailored for the current working queue or the event tree.
Returning nil will dissociate whatever is at that location.
Seldom used by the user, often used by other `e-XXX` functions. Follows arity convention presented in the namespace description. Works like standard `update` but tailored for the current working queue or the event tree. Returning nil will dissociate whatever is at that location.
(end-flow ctx)
Is mainly used to end an infinite
flow.
Can also be used inside a finite
or sampled-finite
flow is it needs to end sooner than expected.
When a flow ends, the rest of the queue that was saved when that flow was created will resume. This behavior makes it extremely easy to chain flows and events, simply add them to the same queue.
Is mainly used to end an [[infinite]] flow. Can also be used inside a [[finite]] or [[sampled-finite]] flow is it needs to end sooner than expected. When a flow ends, the rest of the queue that was saved when that flow was created will resume. This behavior makes it extremely easy to chain flows and events, simply add them to the same queue.
(engine*)
Used for building rank-based event engines.
Unless one is building something creative and/or evil, one should feel satisfied with either
basic-engine
or ptime-engine
. Someone trully interested will study how ptime-engine
is
built before attempting to use this function for building a specific engine. Will only be useful
for modelling a universe where time flows differently (multidimensional? some sort of time travel?)
Returns map containing:
{::period-start (fn [ctx]
"Prepares context for running")
::period-end (fn [ctx]
"Does some clean-up in the context")
::run (fn
([ctx]
"Pops and runs the next ranked event subtree, returns nil if there are not events")
([ctx events]
"Ditto, but uses directly the given events (only useful for some optimizations)"))}
An engine, if it detects that events need to be processed, must call ::period-start. It can then call
::run one or several times, and when all needed events are processed defining some period, the engine
must call ::period-end. For instance, ptime-engine
considers a single point in time as a period
during which events can be further ranked.
Used for building rank-based event engines. Unless one is building something creative and/or evil, one should feel satisfied with either [[basic-engine]] or [[ptime-engine]]. Someone trully interested will study how [[ptime-engine]] is built before attempting to use this function for building a specific engine. Will only be useful for modelling a universe where time flows differently (multidimensional? some sort of time travel?) Returns map containing: ```clojure {::period-start (fn [ctx] "Prepares context for running") ::period-end (fn [ctx] "Does some clean-up in the context") ::run (fn ([ctx] "Pops and runs the next ranked event subtree, returns nil if there are not events") ([ctx events] "Ditto, but uses directly the given events (only useful for some optimizations)"))} ``` An engine, if it detects that events need to be processed, must call ::period-start. It can then call ::run one or several times, and when all needed events are processed defining some period, the engine must call ::period-end. For instance, [[ptime-engine]] considers a single point in time as a period during which events can be further ranked.
(finite duration flow)
(finite duration flow ctx)
Similar to infinite
. However, the flow is meant to last as long as the given duration
.
Knowing the duration
means end-flow
will be called automatically after that interval of time. Also,
before each sample, the ptime is linearly normalized to a value between 0 and 1 inclusive. In simpler terms,
the value at [::e-flat ::ptime]
(also returned by ptime
) is the percentage of completion for that flow.
Samples are automatically scheduled at creation for initialization and at the end for clean-up.
Similar to [[infinite]]. However, the flow is meant to last as long as the given `duration`. Knowing the `duration` means [[end-flow]] will be called automatically after that interval of time. Also, before each sample, the ptime is linearly normalized to a value between 0 and 1 inclusive. In simpler terms, the value at `[::e-flat ::ptime]` (also returned by [[ptime]]) is the percentage of completion for that flow. Samples are automatically scheduled at creation for initialization and at the end for clean-up.
(flow-path ctx)
Returns the path in the flow tree of the currently executing flow.
When a flow is created, it is added to the flow tree ([::flows]
in ctx
) using path
.
When a flow ends, it is removed from the flow tree.
Instead of polluting the global state in the ctx
, if a flow needs some state in order to
work during its lifetime, this is the perfect place to keep it as it will be removed and
garbage collected when the flow ends.
Returns the path in the flow tree of the currently executing flow. When a flow is created, it is added to the flow tree (`[::flows]` in `ctx`) using [[path]]. When a flow ends, it is removed from the flow tree. Instead of polluting the global state in the `ctx`, if a flow needs some state in order to work during its lifetime, this is the perfect place to keep it as it will be removed and garbage collected when the flow ends.
(flowing? ctx)
(flowing? ctx path)
Is the given ctx
or some part of it currently flowing?
Is the given `ctx` or some part of it currently flowing?
(historic engine)
Given an engine, returns a function ctx
-> lazy sequence of each run until all events
are executed.
For instance, given a ptime-engine
, each element in the sequence will be a view of
the ctx
at a specific ptime.
Given an engine, returns a function `ctx` -> lazy sequence of each run until all events are executed. For instance, given a [[ptime-engine]], each element in the sequence will be a view of the `ctx` at a specific ptime.
(infinite flow)
(infinite flow ctx)
When using a ptime-engine
, a flow represent some continuous phenomenon, unlike an event which is
modelled as being instantaneous and having virtually no duration.
A flow is sampled, updated could we say, using a sample
event.
An "infinite" flow is either endless or ends at a moment that is not known in advance (eg. when the context
satifies some condition not knowing when it will occur). It can be ended using end-flow
.
Here is a simple example of an infinite flow that increments a value and schedules samples itself. In other
words, that value will be incremented every 500 time units until it is randomly decided to stop. Then, the rest
of the queue is resumed (event-a
and event-b
after a delay of 150 time units).
(dsim/queue (infinite (fn flow [ctx]
(let [ctx-2 (update-in ctx
(path ctx)
inc)]
(if (< (rand)
0.1)
(end-flow ctx-2)
(rel-conj ctx-2
(rank+ 500)
sample)))))
(wq-delay (rank+ 150))
event-a
event-b)
Note that when a flow is created, it saves the rest of the working queue and will resume execution when it is done.
This designs allows for simply building complex sequences of flows and events, including delays if needed (see
wq-delay
) and repetitions (see [[capture]]).
When created, a flow is sampled right away for initialization. At each sample, a relative ptime is available
under [::e-flat ::ptime]]
(returned by ptime
), starting with 0 at the ptime of creation.
See also flow-path
.
When using a [[ptime-engine]], a flow represent some continuous phenomenon, unlike an event which is modelled as being instantaneous and having virtually no duration. A flow is sampled, updated could we say, using a [[sample]] event. An "infinite" flow is either endless or ends at a moment that is not known in advance (eg. when the context satifies some condition not knowing when it will occur). It can be ended using [[end-flow]]. Here is a simple example of an infinite flow that increments a value and schedules samples itself. In other words, that value will be incremented every 500 time units until it is randomly decided to stop. Then, the rest of the queue is resumed (`event-a` and `event-b` after a delay of 150 time units). ```clojure (dsim/queue (infinite (fn flow [ctx] (let [ctx-2 (update-in ctx (path ctx) inc)] (if (< (rand) 0.1) (end-flow ctx-2) (rel-conj ctx-2 (rank+ 500) sample))))) (wq-delay (rank+ 150)) event-a event-b) ``` Note that when a flow is created, it saves the rest of the working queue and will resume execution when it is done. This designs allows for simply building complex sequences of flows and events, including delays if needed (see [[wq-delay]]) and repetitions (see [[capture]]). When created, a flow is sampled right away for initialization. At each sample, a relative ptime is available under `[::e-flat ::ptime]]` (returned by [[ptime]]), starting with 0 at the ptime of creation. See also [[flow-path]]. ```
(millis->utime millis hz)
Converts an interval in milliseconds to an arbitrary time unit happening hz
times per second.
;; Converting milliseconds to frames for an animation.
;; We know something lasts 2000 milliseconds and the frame-rate is 60 times per second.
;; Hence, it lasts 120 frames.
(= (millis->utime 2000
60)
120)
Converts an interval in milliseconds to an arbitrary time unit happening `hz` times per second. ```clojure ;; Converting milliseconds to frames for an animation. ;; We know something lasts 2000 milliseconds and the frame-rate is 60 times per second. ;; Hence, it lasts 120 frames. (= (millis->utime 2000 60) 120) ```
(minmax-norm min-v interval v)
Min-max normalization, linearly scales x
to fit between 0 and 1 inclusive.
See scale
(arity 3), which is the opposite operation.
(min-max-norm 20
10
25)
0.5
Min-max normalization, linearly scales `x` to fit between 0 and 1 inclusive. See [[scale]](arity 3), which is the opposite operation. ```clojure (min-max-norm 20 10 25) 0.5 ```
(mirror f)
(mirror f ctx)
Many discrete events and flows are typically interested in two things: the path they work on and the current
ptime (ie. the first rank in their ranks, using a ptime-engine
).
Turns f
into a regular event which accepts a ctx
. Underneath, calls (f ctx data-at-path current-ptime)
.
The result is automatically associated in the ctx
at the same path.
Notably useful for finite
and sampled-finite
, and many regular events for that matter.
Many discrete events and flows are typically interested in two things: the path they work on and the current ptime (ie. the first rank in their ranks, using a [[ptime-engine]]). Turns `f` into a regular event which accepts a `ctx`. Underneath, calls `(f ctx data-at-path current-ptime)`. The result is automatically associated in the `ctx` at the same path. Notably useful for [[finite]] and [[sampled-finite]], and many regular events for that matter.
(next-ptime ctx)
On what ptime is scheduled the next event?
Returns nil if there is none.
On what ptime is scheduled the next event? Returns nil if there is none.
(path ctx)
Returns the path of the currently executing flat event (ie. under [::e-flat ::path]
).
Returns the path of the currently executing flat event (ie. under `[::e-flat ::path]`).
(pred-repeat _ctx n)
Example of a predicate meant to be used with wq-sreplay
.
The seed provided to wq-sreplay
, corresponding here to n
, is the number of times a captured queue
will be repeated. For instance, 2 means 3 occurences: the captured queue is first executed, then repeated
twice.
See wq-capture
for an example.
Example of a predicate meant to be used with [[wq-sreplay]]. The seed provided to [[wq-sreplay]], corresponding here to `n`, is the number of times a captured queue will be repeated. For instance, 2 means 3 occurences: the captured queue is first executed, then repeated twice. See [[wq-capture]] for an example.
(ptime ctx)
Returns either the ptime
of the currently executing flat event (ie. under [::e-flat ::ptime]
) or
the global ptime
in the ctx
(ie. under [::ptime]
).
Returns either the ptime at [::e-flat ::ptime]
(notably useful for finite
or sampled-finite
or, if there is none, at [::ptime].
Returns either the `ptime` of the currently executing flat event (ie. under `[::e-flat ::ptime]`) or the global `ptime` in the `ctx` (ie. under `[::ptime]`). Returns either the ptime at `[::e-flat ::ptime]` (notably useful for [[finite]] or [[sampled-finite]] or, if there is none, at [::ptime].
(ptime-engine)
(ptime-engine options)
Like basic-engine
, but treats the first rank of events as a ptime (point in time).
It is essentially a discrete-event simulation engine but serving a whole variety of other purposes as described in the README.
At each run, it executes all events for the next ptime while ensuring that time move forwards. An event can schedule other events in the future or, at the earliest, for the same ptime. Throws at execution if time misbehaves.
Current ptime is associated in the context at ::ptime
(see also ptime
).
options
is a nilable map containing:
k | v |
---|---|
::before | Function ctx -> ctx called right before the first event of the next ptime |
::after | Function ctx -> ctx called after executing all events of a ptime. |
If a ctx does not have any event, a run returns nil.
Like [[basic-engine]], but treats the first rank of events as a ptime (point in time). It is essentially a discrete-event simulation engine but serving a whole variety of other purposes as described in the README. At each run, it executes all events for the next ptime while ensuring that time move forwards. An event can schedule other events in the future or, at the earliest, for the same ptime. Throws at execution if time misbehaves. Current ptime is associated in the context at `::ptime` (see also [[ptime]]). `options` is a nilable map containing: | k | v | |---|---| | ::before | Function ctx -> ctx called right before the first event of the next ptime | | ::after | Function ctx -> ctx called after executing all events of a ptime. | If a ctx does not have any event, a run returns nil.
(queue)
(queue & values)
Clojure has persistent queues but no straightforward way to create them.
Here is one.
Clojure has persistent queues but no straightforward way to create them. Here is one.
(queue? x)
Is x
a persistent queue?
See also queue
.
Is `x` a persistent queue? See also [[queue]].
(rank+ +rank)
(rank+ n-rank +rank)
(rank+ n-rank +rank ctx)
Like ranks+
but optimized for summing only the rank at position n-rank
(defaulting
to 0, the first one).
Commonly used in the context of a ptime-engine
where most of the time we only care about
ptime (ie. the first rank).
See ranks+
for rationale.
(= [42]
(rank+ {::e-flat {::ranks [30]}}
12))
Like [[ranks+]] but optimized for summing only the rank at position `n-rank` (defaulting to 0, the first one). Commonly used in the context of a [[ptime-engine]] where most of the time we only care about ptime (ie. the first rank). See [[ranks+]] for rationale. ```clojure (= [42] (rank+ {::e-flat {::ranks [30]}} 12)) ```
(ranks ctx)
Returns the ranks of the currently executing flat event (ie. under [::e-flat ::ranks]
).
Returns the ranks of the currently executing flat event (ie. under `[::e-flat ::ranks]`).
(ranks+ +ranks)
(ranks+ +ranks ctx)
Returns the ranks of the currently executing flat event summed with the given ones.
Not providing ctx
returns a partially applied version.
Some functions such as rel-conj
or wq-delay
take one as argument for scheduling
something in the future at the same path that the currently executing flat event. Using rank+
or ranks+
comes in handy.
Its sibling, singular rank+
, is optimized for summing only one rank.
(= [10 15 3]
(ranks+ {::e-flat {::ranks [5 5]}}
[5 10 3]))
Returns the ranks of the currently executing flat event summed with the given ones. Not providing `ctx` returns a partially applied version. Some functions such as [[rel-conj]] or [[wq-delay]] take one as argument for scheduling something in the future at the same path that the currently executing flat event. Using [[rank+]] or [[ranks+]] comes in handy. Its sibling, singular [[rank+]], is optimized for summing only one rank. ```clojure (= [10 15 3] (ranks+ {::e-flat {::ranks [5 5]}} [5 10 3])) ```
(reached? ctx ptime-target)
Uses ptime
to tell if a certain ptime has been reached.
Uses [[ptime]] to tell if a certain ptime has been reached.
(rel-conj ctx ctx->ranks event)
Adds event
in the event tree at the same path as the currently executing flat event, at some future ranks.
Typically used for scheduling something in the future related to the current flat event.
See ranks+
for understaning ctx->ranks
. If it returns nil, nothing is scheduled.
Adds `event` in the event tree at the same path as the currently executing flat event, at some future ranks. Typically used for scheduling something in the future related to the current flat event. See [[ranks+]] for understaning `ctx->ranks`. If it returns nil, nothing is scheduled.
(sample)
(sample ctx)
(sample ctx ctx->ranks)
When using a ptime-engine
, samples the flow associated with the current path
.
Sampling is deduplicated on a per-ptime basis. For a given ptime, it is garanteed a flow will be sampled once and only once.
This is especially important considering that a sample event can be scheduled for anywhere in the flow tree. For instance, when drawing a frame in an animation, it is way simpler to sample everything at once, scheduling a sample event at the root (without any path) rather than scheduling manually every single element that needs to be animated.
Hence, a flow can be sampled at different rates by different interested parties without worrying about non-idempotency.
See sampler
.
When using a [[ptime-engine]], samples the flow associated with the current [[path]]. Sampling is deduplicated on a per-ptime basis. For a given ptime, it is garanteed a flow will be sampled once and only once. This is especially important considering that a sample event can be scheduled for anywhere in the flow tree. For instance, when drawing a frame in an animation, it is way simpler to sample everything at once, scheduling a sample event at the root (without any path) rather than scheduling manually every single element that needs to be animated. Hence, a flow can be sampled at different rates by different interested parties without worrying about non-idempotency. See [[sampler]].
(sampled-finite ctx->ranks duration flow)
(sampled-finite ctx->ranks duration flow ctx)
Just like finite
but eases the process of repeatedly sampling the flow.
After each sample, starting at initialization, schedules another one using ctx->ranks
(see the commonly
used rank+
and ranks+
), maxing out the ptime at the ptime of completion so that the forseen interval will
not be exceeded.
Just like [[finite]] but eases the process of repeatedly sampling the flow. After each sample, starting at initialization, schedules another one using `ctx->ranks` (see the commonly used [[rank+]] and [[ranks+]]), maxing out the ptime at the ptime of completion so that the forseen interval will not be exceeded.
(sampler ctx->ranks)
(sampler ctx->ranks ctx)
A sampler
event schedules a sample
at future ranks computed by 'ctx->ranks'. It will
continue to do so until there is nothing flowing anymore for that path
or 'ctx->ranks' returns nil.
It is commonly used for sampling repeatedly a subtree of flows rather than a specific flow. For instance, one could use a sampler for drawing every frame of an animation. Supposing a single ptime represents one millisecond and we draw at 60 frames per second:
(e-conj ctx
[0 1000000]
nil
(sampler (rank+ (/ 1000
60))))
Two things are interesting. First, besides scheduling for ptime 0, the sampler is scheduled for a secondary rank of 1000000, meaning all futures samples it performs, being rescheduled with that same secondary rank, will have a very low priority. Second, we did not provide a path, meaning we want sampling to occur for the whole flow tree (ie. all existing flows).
Sometimes, specific flow samples are ordered using further ranks beyond the ptime. Had we scheduled that sampler without that secondary rank, all future samples would run with the highest priority within ptimes, sampling the whole tree at once, thus disrupting samples that were already ordered for those ptimes in a more specific order.
Ensuring that this sampler executes last garantees ordering of all sample events. Remember that samples are deduplicated, meaning that when a sample ordered by the sampler executes, it will execute only flows that have not been sampled yet.
A [[sampler]] event schedules a [[sample]] at future ranks computed by 'ctx->ranks'. It will continue to do so until there is nothing flowing anymore for that [[path]] or 'ctx->ranks' returns nil. It is commonly used for sampling repeatedly a subtree of flows rather than a specific flow. For instance, one could use a sampler for drawing every frame of an animation. Supposing a single ptime represents one millisecond and we draw at 60 frames per second: ```clojure (e-conj ctx [0 1000000] nil (sampler (rank+ (/ 1000 60)))) ``` Two things are interesting. First, besides scheduling for ptime 0, the sampler is scheduled for a secondary rank of 1000000, meaning all futures samples it performs, being rescheduled with that same secondary rank, will have a very low priority. Second, we did not provide a path, meaning we want sampling to occur for the whole flow tree (ie. all existing flows). Sometimes, specific flow samples are ordered using further ranks beyond the ptime. Had we scheduled that sampler without that secondary rank, all future samples would run with the highest priority within ptimes, sampling the whole tree at once, thus disrupting samples that were already ordered for those ptimes in a more specific order. Ensuring that this sampler executes last garantees ordering of all sample events. Remember that samples are deduplicated, meaning that when a sample ordered by the sampler executes, it will execute only flows that have not been sampled yet.
(scale min-v interval percent)
(scale scaled-min-v scaled-interval min-v interval v)
Linear scaling of numerical values.
Arity | Means |
---|---|
3 | Scales a percent value to be between min-v and (+ min-v interval ) inclusive. & |
5 | Scales v , between min-v and (+ min-v interval ), to be between scaled-min v and (+ scaled-min-v scaled-interval ) inclusive. |
(scale 200
100
0.5)
250
(scale 200
100
2000
1000
2500)
250
Linear scaling of numerical values. | Arity | Means | |---|---| | 3 | Scales a `percent` value to be between `min-v` and (+ `min-v` `interval`) inclusive. & | 5 | Scales `v`, between `min-v` and (+ `min-v` `interval`), to be between `scaled-min`v and (+ `scaled-min-v` `scaled-interval`) inclusive. | ```clojure (scale 200 100 0.5) 250 (scale 200 100 2000 1000 2500) 250 ```
(scheduled? ctx)
(scheduled? ctx ranks)
Is there anything scheduled at all or for the given ranks
?
Is there anything scheduled at all or for the given `ranks`?
It can be particularly useful being able to serialize a ctx
in order to save if to a file or sending
it over the wire (saving the whole state of a game, saving long running simulations, sharing them, etc).
However, how could one serialize all those event functions? The answer to that problem is an external library
called dvlopt/fdat
. The following functions of this API are indeed serializable using dvlopt/fdat
:
It can be particularly useful being able to serialize a `ctx` in order to save if to a file or sending it over the wire (saving the whole state of a game, saving long running simulations, sharing them, etc). However, how could one serialize all those event functions? The answer to that problem is an external library called `dvlopt/fdat`. The following functions of this API are indeed serializable using `dvlopt/fdat`: - finite - infinite - mirror - pred-repeat - rank+ - ranks+ - sample - sampled-finite - sampler - stop - wq-capture - wq-delay - wq-do! - wq-exec - wq-replay - wq-sreplay [https://github.com/dvlopt/fdat.cljc](https://github.com/dvlopt/fdat.cljc)
(stop)
(stop ctx)
Removes anything that is currently being executed (if any), all events and all flows, meaning there is nothing left to run.
Removes anything that is currently being executed (if any), all events and all flows, meaning there is nothing left to run.
(wq-capture)
(wq-capture ctx)
Captures and saves the rest of the working queue. Next call to wq-replay
or wq-sreplay
will replay or clean that captured queue.
This is extremely useful for repeating queues or portion of queues. Without this abilty to capture the current state of a queue, it would be tricky to model activities or successions of flows that need some repetition.
When called more than once, repetitions are nested. For instance:
(queue wq-capture
event-a
wq-capture
event-b
(wq-delay (rank+ 100))
(wq-sreplay pred-repeat
1)
event-c
(wq-replay pred-repeat
1))
;; Equivalent to:
(queue event-a
event-b
(wq-delay (rank+ 100))
event-b
event-c
event-a
event-b
(wq-delay (rank+ 100))
event-b
event-c)
Captures and saves the rest of the working queue. Next call to [[wq-replay]] or [[wq-sreplay]] will replay or clean that captured queue. This is extremely useful for repeating queues or portion of queues. Without this abilty to capture the current state of a queue, it would be tricky to model activities or successions of flows that need some repetition. When called more than once, repetitions are nested. For instance: ```clojure (queue wq-capture event-a wq-capture event-b (wq-delay (rank+ 100)) (wq-sreplay pred-repeat 1) event-c (wq-replay pred-repeat 1)) ;; Equivalent to: (queue event-a event-b (wq-delay (rank+ 100)) event-b event-c event-a event-b (wq-delay (rank+ 100)) event-b event-c) ```
(wq-delay ctx->ranks)
(wq-delay ctx->ranks ctx)
Moves the rest of the working queue to the computed ranks in the event tree.
For instance, inducing a 500 time units delay between 2 events:
(queue event-a
(wq-delay (rank+ 500))
event-b)
Particularly useful for modelling activities (sequences of events dispatched in time, using a ptime-engine
).
Knowing that several events logically bound together at the same path have to be scheduled at different ptimes, one
approach would be to schedule all of them in one go, eargerly. However, that could quickly lead to the event tree
becoming extremely big. More importantly, if an earlier event fails (eg. event-a
), future ones (eg. event-b
) are
already scheduled and will execute.
By using wq-delay
, both problems are solved. All events are part of the same queue, which makes sense, and
delays reschedule the rest of the queue when needed. An event failing means the queue fails, so the activity stops.
An example of an activity, a customer in a bank, assuming some sort of random delays being provided:
(queue customer-arrives
(wq-delay ...)
customer-handled
(wq-delay ...)
customer-leaves)
Unless something more sophisticated is needed, ctx->ranks
will often be the result of rank+
or
ranks+
. If ctx->ranks
returns nil, no delay is incurred.
Moves the rest of the working queue to the computed ranks in the event tree. For instance, inducing a 500 time units delay between 2 events: ```clojure (queue event-a (wq-delay (rank+ 500)) event-b) ``` Particularly useful for modelling activities (sequences of events dispatched in time, using a [[ptime-engine]]). Knowing that several events logically bound together at the same path have to be scheduled at different ptimes, one approach would be to schedule all of them in one go, eargerly. However, that could quickly lead to the event tree becoming extremely big. More importantly, if an earlier event fails (eg. `event-a`), future ones (eg. `event-b`) are already scheduled and will execute. By using [[wq-delay]], both problems are solved. All events are part of the same queue, which makes sense, and delays reschedule the rest of the queue when needed. An event failing means the queue fails, so the activity stops. An example of an activity, a customer in a bank, assuming some sort of random delays being provided: ``` (queue customer-arrives (wq-delay ...) customer-handled (wq-delay ...) customer-leaves) ``` Unless something more sophisticated is needed, `ctx->ranks` will often be the result of [[rank+]] or [[ranks+]]. If `ctx->ranks` returns nil, no delay is incurred.
(wq-dissoc ctx)
Removes the current working queue, stopping effectively its execution.
Removes the current working queue, stopping effectively its execution.
(wq-do! side-effect)
(wq-do! side-effect ctx)
Calls side-effect
with the ctx
to do some side effect. Ignores the result and simply
returns the unmodified ctx
.
Calls `side-effect` with the `ctx` to do some side effect. Ignores the result and simply returns the unmodified `ctx`.
(wq-exec q)
(wq-exec q ctx)
Executes the given event queue q
in isolation from the rest of the current working queue.
See also e-isolate
.
Executes the given event queue `q` in isolation from the rest of the current working queue. See also [[e-isolate]].
(wq-meta ctx)
Returns the metadata of the current working queue.
See also wq-vary-meta
.
Returns the metadata of the current working queue. See also [[wq-vary-meta]].
(wq-replay pred?)
(wq-replay pred? ctx)
When pred?
returns true after being called with the current ctx
, replays the last queue captured by
wq-capture
.
When it returns a falsy value, that last captured queue is removed and the rest of the current working queue is executed.
When `pred?` returns true after being called with the current `ctx`, replays the last queue captured by [[wq-capture]]. When it returns a falsy value, that last captured queue is removed and the rest of the current working queue is executed.
(wq-sreplay pred seed)
(wq-sreplay pred seed ctx)
Similar to wq-replay
but pred
is stateful. It is called with the ctx
and (initially) the seed
.
Returning anything but nil is considered as truthy and is stored as state replacing seed
in the next call.
See [[wq-captured]] for an example with pred-repeat
.
Similar to [[wq-replay]] but `pred` is stateful. It is called with the `ctx` and (initially) the `seed`. Returning anything but nil is considered as truthy and is stored as state replacing `seed` in the next call. See [[wq-captured]] for an example with [[pred-repeat]].
(wq-vary-meta ctx f & args)
Uses Clojure's vary-meta
on the working queue.
When that queue is copied or moved into the future (eg. by calling wq-delay
), it is a convenient way of storing
some state at the level of a queue which can later be retrieved using wq-meta
. When a queue is garbage-collected,
so is its metadata.
Uses Clojure's `vary-meta` on the working queue. When that queue is copied or moved into the future (eg. by calling [[wq-delay]]), it is a convenient way of storing some state at the level of a queue which can later be retrieved using [[wq-meta]]. When a queue is garbage-collected, so is its metadata.
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close