The sketch's condition syntax, checked against the parser rather than recalled
handler-bind takes (Type [name] body ...) and has since it was written; the sketch paired a type with an fn, which is the shape parse.ml names in its own refusal message. load-level had two return types. And there is no defcondition anywhere in the tree -- a condition type is an ordinary struct, which is what both spec-conditions.md and conditions.org say, so the one form in this file that introduced one was inventing it. The header's rules went with them: lowercase-is-a-type-variable and "no sigils" are both the pre-$t spelling, and let never took an annotation.
This commit is contained in:
parent
d94e864dba
commit
0aebef62f3
6
plan.org
6
plan.org
@ -194,8 +194,10 @@ and on a managed ~class~ instance. An ordinary ~struct~ never carries one.
|
||||
|
||||
- Types are mandatory; *inference* makes them feel optional. Annotate function
|
||||
signatures, infer locals — Odin/Zig/Rust ergonomics.
|
||||
- Signatures are annotated as inline name/type pairs, as in ~let~ and
|
||||
~defstruct~: ~(defn area [s Shape] f32 ...)~. No separate ~declare~ form —
|
||||
- Signatures are annotated as inline name/type pairs, as in ~defstruct~ and a
|
||||
~restart-case~ clause: ~(defn area [s Shape] f32 ...)~. A ~let~ is not one of
|
||||
them — a local is inferred from its initialiser and takes no annotation at
|
||||
all. No separate ~declare~ form —
|
||||
~declare~ is kept only where there is no body (forward declarations, FFI).
|
||||
- Annotations at function boundaries are unavoidable, because compile-time
|
||||
overloading is incompatible with full inference. Locals are inferred.
|
||||
|
||||
@ -166,6 +166,12 @@ instead:
|
||||
(defn largest [xs [$t] gt (Fn [$t $t] bool)] (Option $t) ...)
|
||||
```
|
||||
|
||||
The value handed to such a parameter is a named `defn`. An `fn` cannot be written
|
||||
inline into it, because the generic body is checked with nothing substituted and
|
||||
there is no concrete type yet for the `fn`'s own parameters to come from; that
|
||||
restriction lifts at a monomorphic call site, where `reduce`'s and `filter`'s
|
||||
callbacks are ordinary inline `fn`s.
|
||||
|
||||
The alternatives to predicates — compile-time interfaces, or intrinsics
|
||||
restricted to primitives — remain deliberately deferred until the base checker is
|
||||
stable (build sequence milestone 4). The ceiling is that nobody can supply a
|
||||
|
||||
@ -2,11 +2,13 @@
|
||||
;;
|
||||
;; Rules held here:
|
||||
;; - every type notation reads as exactly ONE data item
|
||||
;; - types are inline name/type pairs, as in `let` and `defstruct`
|
||||
;; - types are inline name/type pairs, as in `defstruct` and a restart-case
|
||||
;; clause. NOT in `let`: a local is inferred and takes no annotation
|
||||
;; - the return type is always written; () is unit, a real zero-sized type
|
||||
;; rather than C's void
|
||||
;; - lowercase type names are variables, Capitalized are concrete
|
||||
;; - no `!` convention (nothing is immutable), no `->`, no sigils
|
||||
;; - a type VARIABLE is $t; every other type name is concrete, whatever its
|
||||
;; case. Lowercase-is-a-variable was the first spelling and is gone
|
||||
;; - no `!` convention (nothing is immutable), and no `->`
|
||||
;;
|
||||
;; Normative references: spec-memory.md (ownership, containers, places,
|
||||
;; generics, function values) and spec-conditions.md (restart semantics).
|
||||
@ -91,8 +93,8 @@
|
||||
;; >". Nor can an `fn` be written inline into a (Fn [$t $t] bool) argument: the
|
||||
;; generic body is checked with nothing substituted, so there is no type for the
|
||||
;; fn's own parameters to come from yet. Inside a generic the callback is a
|
||||
;; named defn; at a monomorphic call site the fn can be written where it is
|
||||
;; used, as `centroid` does below.
|
||||
;; named defn; at a monomorphic call site, where the types are already
|
||||
;; concrete, the fn can be written inline where it is used.
|
||||
|
||||
;; Parameters are immutable values; pass a pointer to mutate. `[Enemy]` is a
|
||||
;; borrowed slice — centroid neither owns nor frees the storage.
|
||||
@ -151,7 +153,9 @@
|
||||
;; load-texture cannot know the right recovery — an editor wants a placeholder,
|
||||
;; a release build wants to abort, a hot-reload session wants to retry after the
|
||||
;; file is fixed on disk. So it offers a menu and the caller chooses.
|
||||
(defcondition AssetMissing [path string])
|
||||
;; A condition type is an ordinary struct — there is no defcondition, and no
|
||||
;; class hierarchy to put one in. Matching is by type plus a predicate.
|
||||
(defstruct AssetMissing [path string])
|
||||
|
||||
;; `signal` has type () and RETURNS if every handler returns normally, so the
|
||||
;; fall-through path of a restart-case in value position must still produce the
|
||||
@ -168,10 +172,14 @@
|
||||
|
||||
;; Intermediate frames say nothing about AssetMissing. Nothing to thread.
|
||||
;; invoke-restart has type Never: it does not return to the handler.
|
||||
(defn load-level [path string] () Level
|
||||
(handler-bind [AssetMissing (fn [c]
|
||||
(log "missing asset:" (.path c))
|
||||
(invoke-restart 'use-placeholder))]
|
||||
;; A handler clause is (Type [name] body ...) — the type, then the one binding,
|
||||
;; then the body. It is not a type paired with an `fn`, and a handler closes
|
||||
;; over nothing: it is lifted into its own function, so a value it wants to keep
|
||||
;; goes on the condition or into a global.
|
||||
(defn load-level [path string] Level
|
||||
(handler-bind [(AssetMissing [c]
|
||||
(log "missing asset:" (.path c))
|
||||
(invoke-restart 'use-placeholder))]
|
||||
(parse-level (slurp path))))
|
||||
|
||||
;; A handler that returns normally does not unwind, so the signaller carries on.
|
||||
@ -189,10 +197,9 @@
|
||||
|
||||
(defn collect-parse-errors [src string] (Result Ast)
|
||||
(let [errors (make-vec ParseError)]
|
||||
(handler-bind [ParseError (fn [c]
|
||||
(push errors c) ; value struct: copies out of
|
||||
; the signalling frame
|
||||
(invoke-restart 'skip-form))]
|
||||
(handler-bind [(ParseError [c]
|
||||
(push errors c) ; value struct: copies out of
|
||||
(invoke-restart 'skip-form))] ; the signalling frame
|
||||
(let [ast (parse-all (parser src))]
|
||||
(if (zero? (len errors))
|
||||
(Ok ast)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user