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
|
- Types are mandatory; *inference* makes them feel optional. Annotate function
|
||||||
signatures, infer locals — Odin/Zig/Rust ergonomics.
|
signatures, infer locals — Odin/Zig/Rust ergonomics.
|
||||||
- Signatures are annotated as inline name/type pairs, as in ~let~ and
|
- Signatures are annotated as inline name/type pairs, as in ~defstruct~ and a
|
||||||
~defstruct~: ~(defn area [s Shape] f32 ...)~. No separate ~declare~ form —
|
~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).
|
~declare~ is kept only where there is no body (forward declarations, FFI).
|
||||||
- Annotations at function boundaries are unavoidable, because compile-time
|
- Annotations at function boundaries are unavoidable, because compile-time
|
||||||
overloading is incompatible with full inference. Locals are inferred.
|
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) ...)
|
(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
|
The alternatives to predicates — compile-time interfaces, or intrinsics
|
||||||
restricted to primitives — remain deliberately deferred until the base checker is
|
restricted to primitives — remain deliberately deferred until the base checker is
|
||||||
stable (build sequence milestone 4). The ceiling is that nobody can supply a
|
stable (build sequence milestone 4). The ceiling is that nobody can supply a
|
||||||
|
|||||||
@ -2,11 +2,13 @@
|
|||||||
;;
|
;;
|
||||||
;; Rules held here:
|
;; Rules held here:
|
||||||
;; - every type notation reads as exactly ONE data item
|
;; - 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
|
;; - the return type is always written; () is unit, a real zero-sized type
|
||||||
;; rather than C's void
|
;; rather than C's void
|
||||||
;; - lowercase type names are variables, Capitalized are concrete
|
;; - a type VARIABLE is $t; every other type name is concrete, whatever its
|
||||||
;; - no `!` convention (nothing is immutable), no `->`, no sigils
|
;; 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,
|
;; Normative references: spec-memory.md (ownership, containers, places,
|
||||||
;; generics, function values) and spec-conditions.md (restart semantics).
|
;; 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
|
;; >". 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
|
;; 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
|
;; 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
|
;; named defn; at a monomorphic call site, where the types are already
|
||||||
;; used, as `centroid` does below.
|
;; concrete, the fn can be written inline where it is used.
|
||||||
|
|
||||||
;; Parameters are immutable values; pass a pointer to mutate. `[Enemy]` is a
|
;; Parameters are immutable values; pass a pointer to mutate. `[Enemy]` is a
|
||||||
;; borrowed slice — centroid neither owns nor frees the storage.
|
;; 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,
|
;; 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
|
;; 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.
|
;; 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
|
;; `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
|
;; fall-through path of a restart-case in value position must still produce the
|
||||||
@ -168,8 +172,12 @@
|
|||||||
|
|
||||||
;; Intermediate frames say nothing about AssetMissing. Nothing to thread.
|
;; Intermediate frames say nothing about AssetMissing. Nothing to thread.
|
||||||
;; invoke-restart has type Never: it does not return to the handler.
|
;; invoke-restart has type Never: it does not return to the handler.
|
||||||
(defn load-level [path string] () Level
|
;; A handler clause is (Type [name] body ...) — the type, then the one binding,
|
||||||
(handler-bind [AssetMissing (fn [c]
|
;; 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))
|
(log "missing asset:" (.path c))
|
||||||
(invoke-restart 'use-placeholder))]
|
(invoke-restart 'use-placeholder))]
|
||||||
(parse-level (slurp path))))
|
(parse-level (slurp path))))
|
||||||
@ -189,10 +197,9 @@
|
|||||||
|
|
||||||
(defn collect-parse-errors [src string] (Result Ast)
|
(defn collect-parse-errors [src string] (Result Ast)
|
||||||
(let [errors (make-vec ParseError)]
|
(let [errors (make-vec ParseError)]
|
||||||
(handler-bind [ParseError (fn [c]
|
(handler-bind [(ParseError [c]
|
||||||
(push errors c) ; value struct: copies out of
|
(push errors c) ; value struct: copies out of
|
||||||
; the signalling frame
|
(invoke-restart 'skip-form))] ; the signalling frame
|
||||||
(invoke-restart 'skip-form))]
|
|
||||||
(let [ast (parse-all (parser src))]
|
(let [ast (parse-all (parser src))]
|
||||||
(if (zero? (len errors))
|
(if (zero? (len errors))
|
||||||
(Ok ast)
|
(Ok ast)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user