One DSL shell: a theory (named by scriptType, in scope via
scope) paired with a wisp-indexed model. The invariant tying the
fields together: in scope, scriptType must denote the type
constructor of f — blocks are elaborated at exactly that type, so
the two must agree or the coercion is wrong.
Constructors
forall f. ShellscriptType :: Stringe.g.
"Spell"; blocks check asSpell String/Spell ().scope :: [(String, Maybe String)]The wisp's entire world. The export list is the syscall table: nothing in it may lift IO into
f.warmup :: [String]Sample blocks the warm session compiles at startup to heat the operation code, so the first real block is as fast as the rest. The DSL author knows its own syscalls; e.g.
["roll 6", "help"].commandDocs :: [(String, String)]Optional one-line docs per operation name, surfaced by
:commands. Types are reflected automatically; docs are the one thing hint cannot recover (no Haddock at runtime), so they live here.table :: Table fThe same operations for peers that do not elaborate: a frame that reads as a Call is dispatched from here, no GHC involved.
runScript :: forall a. Wisp -> Emit -> f a -> IO aThe wisp-indexed model: same theory, per-subject algebra.