Skip to content

Commit 7574a3f

Browse files
hyperpolymathclaude
andcommitted
docs(effects): re-land v1 SPEC rule + effect.ml comment fix (Refs #59)
The #207 squash-merge landed only the code commit; the docs commit (235e161) never reached main, leaving SPEC.adoc §3.4 still showing the retired Exn[Error] and lib/effect.ml still claiming Throws[E] is 'not yet threaded' — both now stale/incorrect on main. Re-landing them: - SPEC.adoc §3.4: Exn[Error] → Throws[E]; new 'Effect inference (tracking-only v1)' subsection (catch-less try/? ⇒ Partial; declared rows enforced inferred⊆declared; undeclared permissive); 'Partial by Default' disambiguated from the Partial effect. - lib/effect.ml: corrected the doc-drift comment (#204 threads Throws[E] via name-mangling in Typecheck.lower_effect_expr). Pure docs/comment; gate unchanged. Refs #59 (closed — lineage only, do not reopen). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 73f16b9 commit 7574a3f

2 files changed

Lines changed: 29 additions & 7 deletions

File tree

docs/specs/SPEC.adoc

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -324,11 +324,32 @@ Functions declare effects after `/`:
324324
----
325325
fn pure_fn(x: Int) -> Int / Pure { x + 1 }
326326
fn io_fn() -> () / IO { println("hello") }
327-
fn fallible() -> Int / Exn[Error] { throw(Error::new()) }
328-
fn combined() -> () / IO + Exn[Error] { ... }
329-
----
330-
331-
*Partial by Default:*
327+
fn fallible() -> Int / Throws[Error] { throw(Error::new()) }
328+
fn combined() -> () / IO + Throws[Error] { ... }
329+
----
330+
331+
The v1 effect-row registry (issue #59) pins five canonical names —
332+
`IO`, `Async`, `Partial`, `Throws[E]`, `Mut` — plus reserved
333+
`Random`, `Time`, `Net`. `Throws` is written `Throws[E]` at use
334+
sites; the type argument is threaded (distinct under unification).
335+
The lowercase `io`/`state`/`exn` migration aliases and the older
336+
`Exn` name were retired once the stdlib was renamed to the
337+
canonical names.
338+
339+
*Effect inference (tracking-only v1):*
340+
341+
- A catch-less `try` — including the `e?` desugar (the `?` operator)
342+
— lets failure short-circuit out of the body, so the enclosing
343+
function performs `Partial`. A `try` with a `catch` arm handles the
344+
failure locally and adds no effect.
345+
- When a function declares an effect row explicitly, the inferred row
346+
must be a subset of the declared one (otherwise an effect-mismatch
347+
error is raised). A function with *no* declared row stays permissive
348+
under tracking-only v1 — its effects are not yet enforced.
349+
- Effect *handling* (intercepting/redirecting effects at runtime)
350+
remains out of scope; see `docs/guides/effects-migration-stance.adoc`.
351+
352+
*Partial by Default* (termination, distinct from the `Partial` effect):
332353

333354
- Functions are partial by default (may not terminate)
334355
- `total` functions must provably terminate

lib/effect.ml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,9 @@ let string_of_eff (e : eff) : string =
129129
[docs/guides/effects-migration-stance.adoc]). *)
130130

131131
(** Canonical v1 effect names. [Throws] is written [Throws[E]] at use
132-
sites; the type parameter is carried syntactically but not yet
133-
threaded (tracking-only v1). *)
132+
sites; the type argument is threaded by [Typecheck.lower_effect_expr]
133+
(mangled into the singleton name, so [Throws[A]], [Throws[B]] and
134+
bare [Throws] are distinct under effect unification). *)
134135
let v1_effects = [ "IO"; "Async"; "Partial"; "Throws"; "Mut" ]
135136

136137
(** Reserved for v1.x — recognised so the names are not repurposed, not

0 commit comments

Comments
 (0)