Skuld.Effects.EffectLogger.EffectLogEntry (skuld v0.1.13)

View Source

A flat log entry for an effect invocation.

Each entry represents a single effect handler invocation and captures:

  • id - Unique identifier so wrapped_k can verify it's closing the correct entry
  • sig - Effect signature (module)
  • data - Effect arguments (the input to the effect)
  • value - Result value (if handler called wrapped_k)
  • state - Current state in the effect lifecycle

Flat Log Structure

Entries are stored in a flat list, ordered by when they started. The tree structure of the computation is NOT captured - instead, we use leave_scope handlers to mark entries as :discarded when their continuations are abandoned (e.g., by a Throw effect).

State Machine

The state field tracks where the effect is in its lifecycle:

  • :started - Entry created, handler invoked, continuation not yet completed. This includes effects that have suspended (e.g., Yield) - they remain :started until their continuation is eventually called.

  • :executed - Handler called wrapped_k with a value. The value field contains the result passed to the continuation. Can be short-circuited during replay.

  • :discarded - Handler discarded the continuation (never called wrapped_k). This is the effect that caused the discard (e.g., Throw effect itself). Cannot be short-circuited during replay, must re-execute the handler.

State Transitions

:started  :executed   (wrapped_k called)
:started  :discarded  (leave_scope triggered before wrapped_k called)

Replay Semantics

  • :executed entries can be short-circuited with their logged value
  • :discarded entries must re-execute the handler (they caused the discard)
  • :started entries indicate suspension points (for cold resume)

Summary

Functions

Returns true if the entry can be short-circuited during replay.

Returns true if the entry has completed (handler called wrapped_k).

Reconstruct EffectLogEntry from decoded JSON map.

Check if this entry matches the given effect signature and data.

Create a new effect log entry in :started state.

Transition to :discarded state.

Set the value and transition to :executed state.

Returns true if the entry is in a terminal state.

Types

state()

@type state() :: :started | :executed | :discarded

t()

@type t() :: %Skuld.Effects.EffectLogger.EffectLogEntry{
  data: any(),
  id: String.t(),
  sig: module(),
  state: state(),
  value: any()
}

Functions

can_short_circuit?(effect_log_entry)

@spec can_short_circuit?(t()) :: boolean()

Returns true if the entry can be short-circuited during replay.

Only :executed entries can be short-circuited (they have a value). :discarded entries must be re-executed.

completed?(effect_log_entry)

@spec completed?(t()) :: boolean()

Returns true if the entry has completed (handler called wrapped_k).

from_json(map)

@spec from_json(map()) :: t()

Reconstruct EffectLogEntry from decoded JSON map.

matches?(effect_log_entry, sig, data)

@spec matches?(t(), module(), any()) :: boolean()

Check if this entry matches the given effect signature and data.

new(id, sig, data)

@spec new(String.t(), module(), any()) :: t()

Create a new effect log entry in :started state.

set_discarded(entry)

@spec set_discarded(t()) :: t()

Transition to :discarded state.

Called by leave_scope when a handler doesn't call wrapped_k (e.g., Throw).

set_executed(entry, value)

@spec set_executed(t(), any()) :: t()

Set the value and transition to :executed state.

terminal?(effect_log_entry)

@spec terminal?(t()) :: boolean()

Returns true if the entry is in a terminal state.