Header menu logo Mibo

System Module

Generic system pipeline for composing frame updates with type-enforced snapshot boundaries.

This module provides a pipeline pattern where mutable systems run first (physics, particles), then a snapshot is taken, and readonly systems run on the snapshot. The type system enforces this ordering at compile time.

The pipeline accumulates a single Cmd (not a list) to keep it fast: no list appends, no reversing, and no quadratic behavior as you add phases.

Pattern Overview:

  1. - Begin with mutable model
  2. - Run systems that mutate (physics, AI movement)
  3. - Take readonly snapshot (type changes from Model to Snapshot)
  4. - Run readonly systems (rendering prep, queries)
  5. - Convert back to model and return the accumulated command

Example

 let updateSystems model =
     model
     |> System.start
     |> System.pipeMutable physicsSystem
     |> System.pipeMutable particleSystem
     |> System.snapshot Model.toSnapshot
     |> System.pipe aiDecisionSystem
     |> System.finish Model.fromSnapshot
val updateSystems: model: 'a -> 'b
val model: 'a
namespace System

Functions and values

Function or value Description

dispatch dispatcher arg2

Full Usage: dispatch dispatcher arg2

Parameters:
    dispatcher : 'Snapshot -> Cmd<'Msg>
    arg1 : 'Snapshot * Cmd<'Msg>

Returns: 'Snapshot * Cmd<'Msg>
Modifiers: inline
Type parameters: 'Snapshot, 'Msg

Dispatch commands based on snapshot state.

Use for systems that produce messages without modifying state. The snapshot passes through unchanged.

dispatcher : 'Snapshot -> Cmd<'Msg>
arg1 : 'Snapshot * Cmd<'Msg>
Returns: 'Snapshot * Cmd<'Msg>
Example

 |> System.dispatch (fun snap ->
     if snap.Health <= 0f then Cmd.ofMsg PlayerDied else Cmd.none)
namespace System

dispatchWith selectInput dispatcher arg3

Full Usage: dispatchWith selectInput dispatcher arg3

Parameters:
    selectInput : 'Snapshot -> 'Input voption
    dispatcher : 'Input voption -> 'Snapshot -> Cmd<'Msg>
    arg2 : 'Snapshot * Cmd<'Msg>

Returns: 'Snapshot * Cmd<'Msg>
Modifiers: inline
Type parameters: 'Snapshot, 'Input, 'Msg

Dispatch commands with input selection from snapshot.

Use for encapsulated/autonomous subsystems that:

  • Manage their own internal state (via closure)
  • Receive optional input derived from the snapshot
  • Dispatch commands to communicate with the parent

The selector extracts relevant data from the snapshot, allowing the dispatcher to remain decoupled from the parent's model structure.

selectInput : 'Snapshot -> 'Input voption
dispatcher : 'Input voption -> 'Snapshot -> Cmd<'Msg>
arg2 : 'Snapshot * Cmd<'Msg>
Returns: 'Snapshot * Cmd<'Msg>
Example

 // Autonomous subsystem with internal state (closure)
 let healthTracker : HealthInput voption -> ModelSnapshot -> Cmd<Msg> =
     let mutable hp = 100f
     fun input snap ->
         input |> ValueOption.iter (function
             | TakeDamage amt -> hp <- hp - amt
             | Heal amt -> hp <- min 100f (hp + amt))
         if hp <= 0f then Cmd.ofMsg PlayerDied else Cmd.none

 // Selector bridges parent snapshot to subsystem input
 let selectHealthInput snap =
     if snap.PlayerWasHit then ValueSome (TakeDamage snap.DamageAmount)
     else ValueNone

 // Usage in pipeline
 |> System.dispatchWith selectHealthInput healthTracker
val healthTracker: (obj voption -> obj -> obj)
type 'T voption = ValueOption<'T>
val mutable hp: float32
val input: obj voption
val snap: obj
Multiple items
module ValueOption from Microsoft.FSharp.Core

--------------------
[<Struct>] type ValueOption<'T> = | ValueNone | ValueSome of 'T static member Some: value: 'T -> 'T voption static member op_Implicit: value: 'T -> 'T voption member IsNone: bool with get member IsSome: bool with get member Value: 'T with get static member None: 'T voption with get
val iter: action: ('T -> unit) -> voption: 'T voption -> unit
val amt: float32
val min: e1: 'T -> e2: 'T -> 'T (requires comparison)
val selectHealthInput: snap: 'a -> 'b voption
val snap: 'a
union case ValueOption.ValueSome: 'T -> ValueOption<'T>
union case ValueOption.ValueNone: ValueOption<'T>
namespace System

finish fromSnapshot arg2

Full Usage: finish fromSnapshot arg2

Parameters:
    fromSnapshot : 'Snapshot -> 'Model
    arg1 : 'Snapshot * Cmd<'Msg>

Returns: 'Model * Cmd<'Msg>
Modifiers: inline
Type parameters: 'Snapshot, 'Model, 'Msg

Finish pipeline: convert snapshot back to model and return the accumulated command.

Returns a tuple ready for the Elmish update function.

fromSnapshot : 'Snapshot -> 'Model
arg1 : 'Snapshot * Cmd<'Msg>
Returns: 'Model * Cmd<'Msg>

pipe system arg2

Full Usage: pipe system arg2

Parameters:
    system : 'Snapshot -> 'Snapshot * Cmd<'Msg>
    arg1 : 'Snapshot * Cmd<'Msg>

Returns: 'Snapshot * Cmd<'Msg>
Modifiers: inline
Type parameters: 'Snapshot, 'Msg

Pipe a readonly system (post-snapshot phase).

Use for systems that read state but don't mutate it (rendering prep, AI decisions that only emit commands, query systems).

system : 'Snapshot -> 'Snapshot * Cmd<'Msg>
arg1 : 'Snapshot * Cmd<'Msg>
Returns: 'Snapshot * Cmd<'Msg>

pipeMutable system arg2

Full Usage: pipeMutable system arg2

Parameters:
    system : 'Model -> 'Model * Cmd<'Msg>
    arg1 : 'Model * Cmd<'Msg>

Returns: 'Model * Cmd<'Msg>
Modifiers: inline
Type parameters: 'Model, 'Msg

Pipe a mutable system (pre-snapshot phase).

Use for systems that need to mutate model state (physics, particles). The system receives the model and returns updated model with commands.

system : 'Model -> 'Model * Cmd<'Msg>
arg1 : 'Model * Cmd<'Msg>
Returns: 'Model * Cmd<'Msg>

snapshot toSnapshot arg2

Full Usage: snapshot toSnapshot arg2

Parameters:
    toSnapshot : 'Model -> 'Snapshot
    arg1 : 'Model * Cmd<'Msg>

Returns: 'Snapshot * Cmd<'Msg>
Modifiers: inline
Type parameters: 'Model, 'Snapshot, 'Msg

Transition from mutable Model to readonly Snapshot.

This is the "barrier" in the pipeline. After calling snapshot, only readonly systems (using System.pipe) can be added.

toSnapshot : 'Model -> 'Snapshot
arg1 : 'Model * Cmd<'Msg>
Returns: 'Snapshot * Cmd<'Msg>
Example

 |> System.snapshot Model.toSnapshot
namespace System

start model

Full Usage: start model

Parameters:
    model : 'Model

Returns: 'Model * Cmd<'Msg>
Modifiers: inline
Type parameters: 'Model, 'Msg

Start pipeline with mutable model.

model : 'Model
Returns: 'Model * Cmd<'Msg>

Type something to start searching.