Files
rose-ash/plans/agent-briefings/haskell-loop.md
giles 859361d86a
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 23s
plans: haskell-completeness phases 7-16 + updated loop briefing
String=[Char] via pure-SX views, show, error, numeric tower,
Data.Map, Data.Set, records, IORef, exceptions. Briefing updated
to point at new plan; old phases 1-6 plan untouched.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 17:40:53 +00:00

154 lines
7.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# haskell-on-sx loop agent (single agent, queue-driven)
Role: iterates `plans/haskell-completeness.md` forever. Mini-Haskell 98 with
real laziness (SX thunks are first-class). Phases 16 are complete; this loop
works Phases 716.
```
description: haskell-on-sx queue loop
subagent_type: general-purpose
run_in_background: true
isolation: worktree
```
## Prompt
You are the sole background agent working
`/root/rose-ash-loops/haskell/plans/haskell-completeness.md`. Isolated worktree,
forever, one commit per feature. Push to `origin/loops/haskell` after every commit.
## Restart baseline — check before iterating
1. Read `plans/haskell-completeness.md` — roadmap + Progress log.
2. `ls lib/haskell/` — orient on current state.
3. Run `bash lib/haskell/test.sh`. All 775 tests must be green before new work.
4. Check `lib/haskell/scoreboard.md` — baseline is 156/156 (18 programs).
## The queue
Phase order per `plans/haskell-completeness.md`:
- **Phase 7** — String = [Char] via O(1) string-view dicts. No OCaml changes.
Read the "String-view design" section below before touching anything.
- **Phase 8** — `show` for arbitrary types; `deriving Show` generates proper
instances; `print x = putStrLn (show x)`.
- **Phase 9** — `error` / `undefined`; partial functions raise; top-level runner
catches and a new `hk-test-error` helper checks error messages.
- **Phase 10** — Numeric tower: `fromIntegral`, Float/Double literals,
`sqrt`/`floor`/`ceiling`/`round`/`truncate`, `Fractional`/`Floating` stubs.
- **Phase 11** — `Data.Map` — weight-balanced BST in pure SX in `map.sx`.
- **Phase 12** — `Data.Set` — BST in pure SX in `set.sx`.
- **Phase 13** — `where` in typeclass instances + default methods.
- **Phase 14** — Record syntax: `data Foo = Foo { bar :: Int }`, accessors,
update `r { field = v }`, record patterns.
- **Phase 15** — `IORef` — mutable cells via existing `perform`/`resume` IO.
- **Phase 16** — Exception handling: `catch`, `try`, `throwIO`, `evaluate`.
Within a phase, pick the checkbox with the best tests-per-effort ratio.
Every iteration: implement → test → commit → tick `[ ]` → Progress log → push.
## String-view design (Phase 7 — read before touching strings)
A string view is a pure-SX dict `{:hk-str buf :hk-off n}`. Native SX strings
also satisfy `hk-str?` (offset = 0 implicitly). No OCaml changes needed.
- `hk-str?` covers both native strings and view dicts.
- `hk-str-head v` returns the character at offset `n` as an **integer** (ord
value). Char = integer throughout.
- `hk-str-tail v` returns a new view dict with offset `n+1`; **O(1)**.
- `hk-str-null? v` is true when offset ≥ string length.
- In `match.sx`, the `":"` cons-pattern branch checks `hk-str?` on the scrutinee
**before** the normal tagged-list path. On a string: head = char-int, tail =
shifted view (or `(list "[]")` if exhausted).
- `chr n` converts an integer back to a single-character SX string for display
and for `++`.
- `++` between two strings concatenates natively via `str`; no cons-spine built.
- The natural hazard: any code that checks `(list? v)` or `(= (first v) ":")` on
a value must be audited — string views are dicts, not lists. Check `hk-str?`
first in every dispatch chain.
## Conformance test programs
For each phase's conformance programs:
1. **WebFetch the source** from one of:
- 99 Haskell Problems: https://wiki.haskell.org/H-99:_Ninety-Nine_Haskell_Problems
- Rosetta Code Haskell: https://rosettacode.org/wiki/Category:Haskell
- Self-contained snippets from Real World Haskell / Learn You a Haskell
2. **Adapt minimally** — no GHC extensions, no external packages beyond
`Data.Map`/`Data.Set`/`Data.IORef` (once those phases are done).
3. **Cite the source** as a comment at the top of the `.sx` test file.
4. Add the program name (without `.sx`) to `PROGRAMS` in `lib/haskell/conformance.sh`.
5. Run `bash lib/haskell/conformance.sh` and verify green before committing.
Target: scoreboard grows from 156 → 300+ as phases complete.
## Ground rules (hard)
- **Scope:** only `lib/haskell/**` and `plans/haskell-completeness.md`. Do
**not** edit `spec/`, `hosts/`, `shared/`, other `lib/<lang>/` dirs,
`lib/stdlib.sx`, `lib/` root.
- **NEVER call `sx_build`.** 600s watchdog. If sx_server binary broken →
Blockers entry in the plan, stop.
- **Shared-file issues** → plan's Blockers section with minimal repro.
- **SX thunks** (`make-thunk`, force on use) already in the trampolining
evaluator — reuse. String views are SX dicts, not thunks.
- **SX files:** `sx-tree` MCP tools ONLY (`sx_read_subtree`, `sx_find_all`,
`sx_replace_node`, `sx_insert_child`, `sx_insert_near`,
`sx_replace_by_pattern`, `sx_rename_symbol`, `sx_validate`, `sx_write_file`).
`sx_validate` after every edit. Never `Edit`/`Read`/`Write` on `.sx` files.
- **Shell, Markdown, JSON:** edit with normal tools.
- **Worktree:** commit then push to `origin/loops/haskell`. Never touch `main`.
- **Commit granularity:** one feature per commit.
- **Plan file:** update Progress log + tick boxes every commit.
- **Tests:** `bash lib/haskell/test.sh` must stay green. Never regress existing
775 tests. After new programs, run `bash lib/haskell/conformance.sh`.
## Haskell-specific gotchas
- **String views are dicts** — `(list? v)` returns false for a string view.
Audit every value-dispatch chain in `match.sx` and `eval.sx` for this.
- **Char = integer** — `'a'` parses to int 97. `chr 97 = "a"` (1-char string).
Do not represent Char as a 1-char SX string internally.
- **`deriving Show`** (Phase 8): nested constructor args need parens if their
show string contains a space. Rule: `if string-contains (show arg) " " then
"(" ++ show arg ++ ")" else show arg`.
- **`error` tag** (Phase 9): use `(raise (list "hk-error" msg))`. The top-level
`hk-run-io` guard must catch this tag; do not let `hk-error` leak as an
uncaught SX exception into the test runner's output.
- **`Data.Map` module resolution** (Phase 11): qualified imports `import
qualified Data.Map as Map` need the eval import handler to resolve the dotted
module name to the `map.sx` namespace dict. Check `hk-bind-decls!` import arm.
- **Record update field index** (Phase 14): `r { field = v }` needs the field →
positional-index mapping at runtime. Store it in `hk-constructors` when
registering `:con-rec`.
- **IORef mutation** (Phase 15): `dict-set!` is the SX in-place mutator. The
`IORef` dict is heap-allocated and passed by reference — mutation is safe.
- **Every application arg is a thunk** — `f x y` → `(f (thunk x) (thunk y))`.
Pattern-match forces before matching. Builtins force their args.
- **ADT representation:** `("Just" thunk)`, `("Nothing")`, `(":" h t)`, `("[]")`.
- **Let-polymorphism:** generalise at let-binding boundaries only, not lambda.
- **Typeclass dictionaries:** class = record; instance = record value; method
call = project + apply. Defaults stored under `"__default__ClassName_method"`,
used as fallback when the instance dict lacks the key.
- **Out of scope:** GHC extensions. No `DataKinds`, `GADTs`, `TypeFamilies`,
`TemplateHaskell`. Haskell 98 only.
## General gotchas (all loops)
- SX `do` = R7RS iteration. Use `begin` for multi-expression sequences.
- `cond`/`when`/`let` clauses evaluate only the last expression.
- `type-of` on user fn returns `"lambda"`.
- Shell heredoc `||` gets eaten by bash — escape or use `case`.
- `keys` on an SX dict returns keys in implementation-defined order.
## Style
- No comments in `.sx` unless non-obvious.
- No new planning docs — update `plans/haskell-completeness.md` inline.
- Short, factual commit messages (`haskell: string-view O(1) head/tail (+15)`).
- One feature per iteration. Commit. Log. Next.
Go. Read `plans/haskell-completeness.md`; find the first `[ ]`; implement.