feat(stdlib): async sequencing combinators + Async effect (Refs echidna#62)#471
Open
hyperpolymath wants to merge 1 commit into
Open
feat(stdlib): async sequencing combinators + Async effect (Refs echidna#62)#471hyperpolymath wants to merge 1 commit into
hyperpolymath wants to merge 1 commit into
Conversation
…fs echidna#62) Adds stdlib/future.affine and declares `effect Async;` in stdlib/effects.affine — the async primitive for the ReScript->AffineScript migration (echidna#62; Client.res's `promise<result<T, string>>` chains via Promise.then/catch/resolve). Model (thin combinators over Result + effect; user-chosen approach): on the Deno-ESM target the compiler emits native JS async/await and host promises cross as the Thenable extern ABI (#103) — suspension is at the extern boundary (echidna#61 Http), so the source needs no promise monad. An async value is its settled `Result<T, String>` (Client.res's `result<_, string>`), carried by an `/{Async}`-effect function. future.affine is the value-level half: a 1:1 map of the ReScript promise chain onto that Result. No wrapper type by necessity, not just preference: a user-defined generic `Async<T>` (ADT or alias) is unusable in signatures — the typechecker raises "Too many arguments for kind"; only prelude's multi-constructor `Option`/`Result` are sound generic carriers. This is a real AffineScript compiler limitation (single-constructor / aliased generic types) — recorded for a follow-up affinescript issue. `Result<T, String>` is also exactly Client.res's existing shape. Surface: resolve (Promise.resolve) / reject / then (Promise.then, async step) / map_ok (then with pure mapper) / recover (Promise.catch) / map_err. effects.affine now declares `effect Async;` (the #196 v1 registry already reserved the name; Vscode.affine already used `/ Async` — this closes the stdlib coherence gap). Verified: #136 stdlib-wide AOT smoke gate drives the new file + modified effects.affine through resolve -> typecheck -> borrow -> Deno-ESM codegen; `dune runtest` green incl. new "AOT future.affine" case and unchanged "AOT effects.affine". Regression-protected on merge. echidna#62 stays open as the consumer-side tracker per its protocol (closes when the Client.res port lands, not here). Independent of echidna#63/#64 (no code import) — independent PR off main. Next: #61 http.affine (Deno fetch extern -> the /{Async} boundary; where the String->Json parse bridge lands). Refs #128, hyperpolymath/echidna#62. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Single-commit stdlib addition:
asyncmodule with sequencing combinators + declares theAsynceffect. Part of the affinescript stdlib roadmap (#412); refs echidna#62.Recovered from local-only WIP branch during 2026-05-30 estate housekeeping pass.