Effect

:= [
    CloseModal(Str),
    ConsoleLog(Str),
    CryptoDigest(Str, List(U8), Box(List(U8) -> Box(msg))),
    CryptoDigestFile(Str, U32, U64, U64, Box(List(U8) -> Box(msg))),
    HttpSend(Str, Str, List({ name : Str, value : Str }), List(U8), U64, Box({ status : U16, headers : List({ name : Str, value : Str }), body : List(U8) } -> Box(msg))),
    HttpSendFile(Str, Str, List({ name : Str, value : Str }), U32, U64, U64, U64, Box({ status : U16, headers : List({ name : Str, value : Str }), body : List(U8) } -> Box(msg))),
    Navigate(Str),
    PortSend(Str, Str),
    PushUrl(Str),
    ReplaceUrl(Str),
    ShowModal(Str),
    TimeAfter(U32, Box(I64 -> Box(msg))),
    TimeCancel(Str),
    TimeDebounce(Str, U32, Box(I64 -> Box(msg))),
]

An effect: an asynchronous action described as *data*, returned from init or update and executed by the host. The response callback is a real typed function (... -> msg), boxed so the host can store and call it without knowing the app's Msg layout.

Why data instead of effectful platform functions: hosted functions are monomorphic C symbols, so they cannot accept a callback that is generic over the app's msg. Effects flow through update's return type, where msg is properly in scope. Msg-free effects (logging, navigation, modals, timer cancellation) are data too: as data they can be matched on, so a pure test can assert exactly which effects an update produced. The boundary rule: every app entrypoint is pure and the compiler enforces it, every observable effect is an Effect value returned from init or update, and init receives the app's flags string, into which the embedder puts any boot data the app needs (time, url, whatever). Recurring event sources are subscriptions (see Sub).

Apps normally use the constructors in Http, Time and WebCrypto rather than these variants directly. Payload fields are positional for a simpler host walk. File ids come from a file input's Attribute.on_file; the browser side holds the actual File object, so its bytes never cross into wasm unless you hash or upload them.

map : Effect(a), (a -> b) -> Effect(b)

Re-target an effect to a parent message type: the response callback's message is passed through f on its way to update, so components can own their effects too.