Evaluator¶
The small-step reference evaluator.
evaluator
¶
Small-step reference evaluator for the Quivers Indexed Effect Core.
The evaluator is deliberately an interpreter, not an optimized execution
engine. It gives Return, Bind, Perform, and Handle one
operational meaning against which lowerings and backend runtimes can be tested.
Core terms remain serializable: host values and executable handler clauses live
only in :class:RuntimeAttachments and are addressed by stable QIEC IDs.
Handlers are lexical and deep. A resumption reinstalls the matched handler and every inner continuation frame, whereas a handler clause is evaluated only in the outer context. This distinction is easiest to make explicit with the CEK machine below: handling an operation splits the continuation at its matching handler boundary.
RuntimeValidator
¶
A predicate a host value must pass to inhabit a QIEC type.
It returns False to reject the value; True or None accepts it.
OperationClause
¶
A host implementation of one handler operation clause.
It receives the request, the delimited continuation, and the clause's
runtime services, and returns the clause's answer, a :class:Forward, or a
:class:TailResume.
ReturnClause
¶
A host implementation of a handler's return clause.
It receives the handled computation's final value and the clause's runtime services, and returns the handler's answer.
ResponseHook
¶
A callback applied to the reply a forwarded request receives.
It returns the value the resumed computation receives in place of the reply.
EvaluationTraceHook
¶
A callback receiving each evaluator event's name and detail mapping.
EvaluationError
¶
Bases: RuntimeError
Base class for failures at the typed-core/runtime boundary.
MissingAttachmentError
¶
Bases: EvaluationError
A stable runtime reference has no value or handler attachment.
RuntimeTypeMismatch
¶
Bases: EvaluationError
A host result failed the validator for its QIEC result type.
FuelExhaustedError
¶
Bases: EvaluationError
The step budget ran out before the computation finished.
General recursion is allowed to diverge, so a budget is the only way a caller can bound a run. Exhaustion is reported as an ordinary evaluation failure rather than a host recursion error, which the machine's explicit stack never raises.
| PARAMETER | DESCRIPTION |
|---|---|
steps
|
The budget that was exhausted; kept on the error as
TYPE:
|
Source code in src/quivers/qiec/evaluator.py
UnknownComputationError
¶
Bases: EvaluationError
A call names a computation the evaluator was not given a body for.
UnhandledEffectError
¶
UnhandledEffectError(request: EffectRequest)
Bases: EvaluationError
No enclosing lexical handler accepts an effect request.
| PARAMETER | DESCRIPTION |
|---|---|
request
|
The request nothing handled; kept on the error as
TYPE:
|
Source code in src/quivers/qiec/evaluator.py
InvalidHandlerError
¶
Bases: EvaluationError
A runtime handler contradicts its checked structural signature.
HandlerManifest
dataclass
¶
HandlerManifest(definitions: Mapping[HandlerId, HandlerDef])
Immutable checked handler definitions accepted by an evaluator.
Construct this from a :class:KernelRegistry after its declarations have
passed kernel registration. Runtime clause objects are then accepted only
when their complete structural definitions equal the manifest entry, not
merely when their stable IDs collide.
| PARAMETER | DESCRIPTION |
|---|---|
definitions
|
The checked handler definitions by identity.
TYPE:
|
__post_init__
¶
Freeze the definitions behind a read-only view.
The manifest is what a runtime resolves a handler through, so it is copied and wrapped rather than aliased: a caller mutating the mapping it passed in would otherwise change which handler a running computation reaches.
Source code in src/quivers/qiec/evaluator.py
from_registry
classmethod
¶
from_registry(registry: KernelRegistry) -> HandlerManifest
Build a manifest from a checked registry.
| PARAMETER | DESCRIPTION |
|---|---|
registry
|
A registry whose handlers have already been checked.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
HandlerManifest
|
A manifest over those handlers. |
Source code in src/quivers/qiec/evaluator.py
ResumptionUsageError
¶
Bases: EvaluationError
A handler clause used its resumption outside the declared grade.
NonDuplicableContinuationError
¶
Bases: ResumptionUsageError
An unrestricted clause captured state that cannot safely be copied.
RuntimeConstructor
dataclass
¶
RuntimeConstructor(constructor: object, static_arguments: tuple[object, ...], fields: tuple[object, ...], result_type: TypeExpr)
Erased runtime representation of a checked constructor value.
| PARAMETER | DESCRIPTION |
|---|---|
constructor
|
The constructor's stable identity.
TYPE:
|
static_arguments
|
The constructor's telescope instantiation, as evaluated static data.
TYPE:
|
fields
|
The evaluated field values, in declaration order.
TYPE:
|
result_type
|
The family type the value inhabits.
TYPE:
|
AttachmentBinding
dataclass
¶
AttachmentBinding(value: object, type: TypeExpr, validator: RuntimeValidator, duplicable: bool = False)
One host value attached to an otherwise serializable core term.
duplicable is a semantic assertion about the host value, not merely a
promise that copy.copy happens to work. Multi-shot resumptions reject
captured attachment values unless this bit was supplied explicitly.
| PARAMETER | DESCRIPTION |
|---|---|
value
|
The host value.
TYPE:
|
type
|
The type the value inhabits.
TYPE:
|
validator
|
The predicate that checks a host value against
TYPE:
|
duplicable
|
Whether an unrestricted resumption may capture the value.
TYPE:
|
RuntimeClause
dataclass
¶
RuntimeClause(invoke: OperationClause, result_validator: RuntimeValidator)
Executable operation clause and validator for the resumed value.
| PARAMETER | DESCRIPTION |
|---|---|
invoke
|
The clause body, called with the request, its resumption, and a clause context.
TYPE:
|
result_validator
|
The predicate every value resumed through this clause must pass.
TYPE:
|
RuntimeHandler
dataclass
¶
RuntimeHandler(definition: HandlerDef, clauses: Mapping[OperationId, RuntimeClause], return_clause: ReturnClause = _identity_return, input_validator: RuntimeValidator = _accept, output_validator: RuntimeValidator = _accept, duplicable_context: bool = False, mutable_context: bool = False, fork_context: Callable[['RuntimeHandler'], 'RuntimeHandler'] | None = None, context_factory: Callable[[], 'RuntimeHandler'] | None = None, on_enter: Callable[[], None] | None = None, on_exit: Callable[[], None] | None = None, on_drop: Callable[[], None] | None = None)
Executable attachment for a structural :class:HandlerDef.
The checked definition contains coverage, grades, input/output types, and introduced effects. This attachment contains only process-local code and state. It is never serialized as QIEC.
| PARAMETER | DESCRIPTION |
|---|---|
definition
|
The checked declaration this attachment implements.
TYPE:
|
clauses
|
One runtime clause per covered operation, by identity.
TYPE:
|
return_clause
|
How the handler answers the computation's return; the identity return by default.
TYPE:
|
input_validator
|
The predicate the handled computation's result must pass.
TYPE:
|
output_validator
|
The predicate the handler's answer must pass.
TYPE:
|
duplicable_context
|
Whether an unrestricted resumption may capture an installation of this handler.
TYPE:
|
mutable_context
|
Whether an installation carries state; such a handler needs a
TYPE:
|
fork_context
|
Builds an independent copy of an installation for another shot; required when the context is both mutable and duplicable.
TYPE:
|
context_factory
|
Builds a fresh installation each time the handler is installed.
TYPE:
|
on_enter
|
Called when an installation is entered.
TYPE:
|
on_exit
|
Called once when the handled computation completes.
TYPE:
|
on_drop
|
Called once when the handled computation is abandoned instead;
exclusive with
TYPE:
|
__post_init__
¶
Check the executable clauses against the checked declaration.
| RAISES | DESCRIPTION |
|---|---|
InvalidHandlerError
|
If the runtime implements an operation the declaration does not cover, or leaves a declared one unimplemented. Both directions matter: an extra clause would never be dispatched to, and a missing one would fail only when that operation was first performed, perhaps long after the handler was installed. |
Source code in src/quivers/qiec/evaluator.py
RuntimeAttachments
dataclass
¶
RuntimeAttachments(values: dict[AttachmentId, AttachmentBinding] = dict(), handlers: dict[HandlerId, RuntimeHandler] = dict())
Process-local values and handlers keyed by stable core identifiers.
| PARAMETER | DESCRIPTION |
|---|---|
values
|
Attached host values by attachment identity.
TYPE:
|
handlers
|
Runtime handlers by handler identity.
TYPE:
|
bind_value
¶
bind_value(attachment: AttachmentId, value: object, type: TypeExpr, *, validator: RuntimeValidator = _accept, duplicable: bool = False) -> AttachmentRef
Attach a host value and return its stable core reference.
| PARAMETER | DESCRIPTION |
|---|---|
attachment
|
The identity the core term refers to the value by.
TYPE:
|
value
|
The host value.
TYPE:
|
type
|
The type the core ascribes to it.
TYPE:
|
validator
|
Checks the value really inhabits that type. The default accepts anything, for a value the static check already settles.
TYPE:
|
duplicable
|
Whether the value may be copied. This is an assertion about the value, not a guess: a multi-shot resumption capturing a non-duplicable attachment is refused, because copying it would give two continuations a shared mutable thing.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
AttachmentRef
|
The core reference to use in a term. |
| RAISES | DESCRIPTION |
|---|---|
InvalidHandlerError
|
If the identity is already bound to a different value, type, validator, or duplicability. Rebinding is refused rather than overwriting, since a term already built would silently start meaning something else. |
RuntimeValidationError
|
If the validator rejects the value. |
Source code in src/quivers/qiec/evaluator.py
bind_handler
¶
bind_handler(handler: RuntimeHandler) -> HandlerId
Attach executable clauses to their structural handler identity.
| PARAMETER | DESCRIPTION |
|---|---|
handler
|
The executable handler, already checked against its declaration.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
HandlerId
|
The identity it was bound under. |
| RAISES | DESCRIPTION |
|---|---|
InvalidHandlerError
|
If a different handler is already bound to that identity. |
Source code in src/quivers/qiec/evaluator.py
RuntimeRequest
dataclass
¶
RuntimeRequest(core: EffectRequest, arguments: tuple[object, ...], resumption_path: tuple[int, ...], dynamic_path: tuple[DynamicAddressFrame, ...] = ())
An evaluated request supplied to a process-local handler clause.
| PARAMETER | DESCRIPTION |
|---|---|
core
|
The stable request as written, before evaluation.
TYPE:
|
arguments
|
The evaluated value arguments, in order.
TYPE:
|
resumption_path
|
The ordinal of each resumption taken to reach this request.
TYPE:
|
dynamic_path
|
The call and local-instance frames live when the request was performed, outermost first, so one site reached through two recursive iterations yields two addresses.
TYPE:
|
instance
property
¶
instance: EffectInstanceId
The lexical instance this request was performed on.
| RETURNS | DESCRIPTION |
|---|---|
EffectInstanceId
|
The instance, which decides which handler answers. |
operation
property
¶
operation: OperationId
The operation requested.
| RETURNS | DESCRIPTION |
|---|---|
OperationId
|
The operation, which decides which clause answers. |
address
property
¶
Return the static, dynamic, and multi-shot address components.
| RETURNS | DESCRIPTION |
|---|---|
tuple[str, tuple[tuple[str, str | int], ...], tuple[int, ...]]
|
The source site, the dynamic address frames, and the resumption path. One request site reached twice, under a loop or under a resumed continuation, yields two addresses, which is what lets a trace name each occurrence separately. |
ClauseComputation
dataclass
¶
ClauseComputation(computation: Computation, bindings: tuple[tuple[Local, object], ...] = ())
Ask the evaluator to run a structural clause body outside the handler.
Host values introduced by a handler must first be installed through
:meth:ClauseContext.attach; arbitrary callback closures do not enter the
computation tree.
| PARAMETER | DESCRIPTION |
|---|---|
computation
|
The stable computation to run.
TYPE:
|
bindings
|
Locals the computation refers to, each with its evaluated value.
TYPE:
|
Forward
dataclass
¶
Forward(on_response: ResponseHook | None = None)
Forward a request to an outer handler, optionally observing its reply.
| PARAMETER | DESCRIPTION |
|---|---|
on_response
|
Called with the outer handler's answer before it reaches the
resumed computation, or
TYPE:
|
TailResume
dataclass
¶
Resume a clause's continuation in place, on the machine's own stack.
A foreign clause that answers with this resumes once, exactly as an
authored resume(value) in tail position does: the captured frames
return to the machine's stack and the handler's return clause applies
when the computation completes. Unlike calling the resumption from
the clause, which drives the continuation in a nested host call that
stays pending until it returns, this leaves no host frame behind, so a
multi-shot resumption captured later inside the same handler may run
the continuation any number of times.
| PARAMETER | DESCRIPTION |
|---|---|
value
|
What the resumed operation supplies.
TYPE:
|
ContinuationFrame
¶
One frame of the reference evaluator's explicit continuation stack.
The evaluator creates and consumes every frame. A handler clause sees
frames only through the :class:ClauseContext and :class:Resumption
the evaluator hands it, and never inspects or builds one itself; the
class exists so those two constructors can name the stack they capture.
ClauseContext
¶
ClauseContext(evaluator: Evaluator, environment: Mapping[Local, object], outer_stack: tuple[ContinuationFrame, ...], resumption_path: tuple[int, ...], request: RuntimeRequest | None)
Disciplined runtime services available to an attached handler clause.
| PARAMETER | DESCRIPTION |
|---|---|
evaluator
|
The evaluator running the clause.
TYPE:
|
environment
|
The bindings in scope at the handler.
TYPE:
|
outer_stack
|
The continuation frames outside the handler.
TYPE:
|
resumption_path
|
The ordinal of each resumption taken to reach the clause.
TYPE:
|
request
|
The request the clause answers, or
TYPE:
|
Source code in src/quivers/qiec/evaluator.py
request
property
¶
request: RuntimeRequest | None
The request this clause is answering.
| RETURNS | DESCRIPTION |
|---|---|
RuntimeRequest or None
|
The request, or None in a return clause, which answers a completed computation rather than an operation. |
attachments
property
¶
attachments: RuntimeAttachments
The host values available to this clause.
| RETURNS | DESCRIPTION |
|---|---|
RuntimeAttachments
|
The evaluator's attachment table. |
evaluate
¶
evaluate(computation: Computation) -> object
Evaluate a clause body in the outer handler context.
A delimiter prevents the clause body from consuming the continuation outside the handled expression. Effects performed here can reach only handlers outside the matched handler, which is the chosen deep-handler semantics.
| PARAMETER | DESCRIPTION |
|---|---|
computation
|
The clause body to run.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
object
|
What the body produced. |
Source code in src/quivers/qiec/evaluator.py
attach
¶
attach(value: object, type: TypeExpr, *, role: str, validator: RuntimeValidator = _accept, duplicable: bool = False) -> AttachmentRef
Install a generated host value under a deterministic runtime ID.
| PARAMETER | DESCRIPTION |
|---|---|
value
|
The host value to attach.
TYPE:
|
type
|
The type the core ascribes to it.
TYPE:
|
role
|
What the value is for, which enters its derived identity.
TYPE:
|
validator
|
Checks the value inhabits the type.
TYPE:
|
duplicable
|
Whether the value may be copied by a multi-shot resumption.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
AttachmentRef
|
A reference usable in a core term. The identity derives from the run, the request, and the role rather than being generated, so a trace can name the same attachment twice. |
Source code in src/quivers/qiec/evaluator.py
Resumption
¶
Resumption(evaluator: Evaluator, request: RuntimeRequest, grade: ResumptionGrade, captured_environment: Mapping[Local, object], captured_stack: tuple[ContinuationFrame, ...], outer_stack: tuple[ContinuationFrame, ...], validator: RuntimeValidator, path: tuple[int, ...])
Dynamically checked, delimited continuation supplied to one clause.
| PARAMETER | DESCRIPTION |
|---|---|
evaluator
|
The evaluator that captured the continuation.
TYPE:
|
request
|
The request whose result the continuation awaits.
TYPE:
|
grade
|
How often the clause may invoke the continuation.
TYPE:
|
captured_environment
|
The bindings in scope at the request.
TYPE:
|
captured_stack
|
The continuation frames between the request and the handler.
TYPE:
|
outer_stack
|
The continuation frames outside the handler.
TYPE:
|
validator
|
The predicate every resumed value must pass.
TYPE:
|
path
|
The ordinal of each resumption taken to reach the clause.
TYPE:
|
Source code in src/quivers/qiec/evaluator.py
grade
property
¶
grade: ResumptionGrade
The grade this resumption is held to.
| RETURNS | DESCRIPTION |
|---|---|
ResumptionGrade
|
The declared grade, checked statically and again here. |
calls
property
¶
How many times this resumption has been invoked so far.
| RETURNS | DESCRIPTION |
|---|---|
int
|
The count, which the grade bounds. |
__call__
¶
Resume the suspended computation with a value.
The static analysis already rejects a clause that can exceed its grade. This guard stays because it protects against a foreign handler, whose body the analysis never saw, and against a compiler bug: a grade is what lets a runtime discard a continuation, so exceeding it is not recoverable.
| PARAMETER | DESCRIPTION |
|---|---|
value
|
What the resumed operation supplies.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
object
|
What the resumed computation produced. |
| RAISES | DESCRIPTION |
|---|---|
ResumptionUsageError
|
If the grade is zero, or an affine or linear resumption is invoked more than once. |
NonDuplicableContinuationError
|
If an unrestricted resumption would have to copy a captured value that is not duplicable. |
RuntimeValidationError
|
If the value does not inhabit the operation's result type. |
Source code in src/quivers/qiec/evaluator.py
Evaluator
¶
Evaluator(attachments: RuntimeAttachments | None = None, *, handler_manifest: HandlerManifest | None = None, trace_hook: EvaluationTraceHook | None = None, module: QiecModule | None = None, fuel: int | None = None, type_validator: Callable[[TypeExpr], RuntimeValidator | None] | None = None)
Execute QIEC computations with explicit runtime attachments.
| PARAMETER | DESCRIPTION |
|---|---|
attachments
|
The host values and handlers available; empty by default.
TYPE:
|
handler_manifest
|
Checked handler definitions every attached handler must match
exactly on each :meth:
TYPE:
|
trace_hook
|
Called with each execution event's name and payload, or
TYPE:
|
module
|
The module whose named computations calls resolve to and whose
authored handlers
TYPE:
|
fuel
|
The number of machine steps a run may take before failing with
:class:
TYPE:
|
type_validator
|
Supplies the host validator for a type at an authored handler's
boundaries: the values it is resumed with, the handled
computation's result, and its answer.
TYPE:
|
Source code in src/quivers/qiec/evaluator.py
evaluate
¶
evaluate(computation: Computation, environment: Mapping[Local, object] | None = None) -> object
Evaluate a closed or explicitly supplied computation.
| PARAMETER | DESCRIPTION |
|---|---|
computation
|
The computation to run.
TYPE:
|
environment
|
Values for the computation's free locals. None means it is closed.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
object
|
What the computation produced. |
| RAISES | DESCRIPTION |
|---|---|
EvaluationError
|
If a request reaches no handler, a handler is missing from the manifest, a resumption exceeds its grade, or a host value fails validation. |
Source code in src/quivers/qiec/evaluator.py
evaluate_checked
¶
evaluate_checked(computation: Computation, registry: KernelRegistry, environment: Mapping[Local, object] | None = None) -> object
Kernel-check a computation and fail closed on handler attachments.
| PARAMETER | DESCRIPTION |
|---|---|
computation
|
The computation to run.
TYPE:
|
registry
|
Declarations to check it against.
TYPE:
|
environment
|
Values for its free locals.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
object
|
What the computation produced. |
| RAISES | DESCRIPTION |
|---|---|
KernelError
|
If the computation does not check. |
EvaluationError
|
If execution fails, as in |
Source code in src/quivers/qiec/evaluator.py
evaluate_validated
¶
evaluate_validated(computation: Computation, registry: KernelRegistry, environment: Mapping[Local, object] | None = None) -> object
Run a computation a module validation has already checked.
validate_module checks every body of a module against its
registry; a caller holding that registry runs such a body
without checking it again. The handler manifest is still held
against the attachments.
| PARAMETER | DESCRIPTION |
|---|---|
computation
|
The computation to run, a body of the validated module.
TYPE:
|
registry
|
The registry the module validated against.
TYPE:
|
environment
|
Values for its free locals.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
object
|
What the computation produced. |
| RAISES | DESCRIPTION |
|---|---|
EvaluationError
|
If execution fails, as in |
Source code in src/quivers/qiec/evaluator.py
evaluate_value
¶
Erase and evaluate a checked QIEC value.
| PARAMETER | DESCRIPTION |
|---|---|
value
|
The value to evaluate.
TYPE:
|
environment
|
Values for its free locals.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
object
|
The host representation of the value. |