Structuring FRP (specifically Note) applications

I guess you mean dependency order. So yes if you have an event/signal that depends on another one you have to define the later before, like values in general in OCaml.

In your particular case I suggest to handle the triggering of the asynchronous computation in the update function and feedback the result into the FRP system by using a primitive event.

This leads to the following code:

open Brr
open Brr_note
open Note

let data_loader : unit -> [> `Data of int] E.t * (unit -> unit) =
fun () ->
  let ev, send = E.create () in
  let load () = let fut = Fut.return (`Data 1) in Fut.await fut send in
  ev, load

type state = { data_count : int }
let initial_state = { data_count = 0 }
let update load_data action state = match action with
| `Data v -> { data_count = state.data_count + v }
| `Reset -> { data_count = 0 }
| `Incr -> load_data (); state
| _ -> state

let build_ui_component (count: int signal) tag =
  let button = El.button [] in
  let ev = Evr.on_el Ev.click (fun _ -> tag) button in
  El.div [ button ], ev

let application =
  let data_loaded, load_data = data_loader () in
  let def state =
    let count = S.map ~eq:Int.equal (fun v -> v.data_count) state in
    let incr, ev1 = build_ui_component count `Incr in
    let reset, ev2 = build_ui_component count `Reset in
    let action = E.select [ev1; ev2; data_loaded] in
    let update = E.map (update load_data) action in
    let state' = S.accum (S.value state) update in
    state', (state', [incr; reset])
  in
  S.fix initial_state def
3 Likes