swap!, reverse!, sort!, sort-by!, index-of, min-of, max-of, map!, reduce and filter, each written once over $t. Every call site in the corpus moves with them. min-of and max-of are not min and max because min and max are builtins over two or more numbers and nothing shadows a builtin. These reduce a slice, which is a different operation at a different arity. sort-bytes! did not collapse into sort!, and the reason is the point of the predicates: a [u8] is not ordered? and cannot be, because < is an instruction and comparing two slices lexicographically is a loop. It is sort-by! with bytes<? written in, one line, keeping its name and its stability note. sum-i32/sum-f32 and append-i64!/append-f64! stay for the reasons the spike gave. Not what the notes predicted: none of the ten collapses on a signature change alone. filter and reduce need copyable? because the checker demands it - reduce's accumulator at (Vec i32) is a double move - and the rest declare it because a slice of owning elements would have them duplicating headers.
106 lines
3.6 KiB
Plaintext
106 lines
3.6 KiB
Plaintext
;;;; Generics by monomorphisation, end to end.
|
|
;;;;
|
|
;;;; A [$t] binds a type variable in a defn signature and every call site
|
|
;;;; instantiates the body at the types it passes. The body is checked once
|
|
;;;; *abstractly*, with nothing substituted, so an operator the variable is
|
|
;;;; not declared to support is refused at the definition and not at whichever
|
|
;;;; call site happened to reach a type that worked — see generic-reject.flan
|
|
;;;; and generic-runaway.flan for that half.
|
|
;;;;
|
|
;;;; What this program is asserting, in order: one variable at several types,
|
|
;;;; a variable bound inside a slice, a generic calling a generic at its own
|
|
;;;; variable so that instantiation has to be transitive, the four where
|
|
;;;; predicates, two variables at once, println deferred to the instantiation,
|
|
;;;; and the collapsed prelude family the whole feature was for.
|
|
|
|
;; One variable, several types, and (ident 3) and (ident 7) share one copy.
|
|
;; The identity needs its parameter once, so it needs nothing declared: a type
|
|
;; variable is move-only by default and one move is what this is.
|
|
(defn ident [x $t] $t x)
|
|
|
|
;; The variable is bound *inside* a type constructor, which is a structural
|
|
;; walk rather than a name match.
|
|
(defn first-or [s [$t] d $t] $t
|
|
{:where (copyable? $t)}
|
|
(if (= (len s) 0) d (at s 0)))
|
|
|
|
;; A generic calling a generic at its own variable: the copy of [swap!] is
|
|
;; generated when [rotate!] is instantiated and not before.
|
|
(defn rotate! [s [$t]] ()
|
|
{:where (copyable? $t)}
|
|
(dotimes [i (- (len s) 1)]
|
|
(swap! s i (+ i 1))))
|
|
|
|
;; numeric? admits + - * / %.
|
|
(defn twice [x $t] $t
|
|
{:where (numeric? $t)}
|
|
(+ x x))
|
|
|
|
;; equal? admits = and !=; ordered? admits < <= > >= min max, and entails
|
|
;; equal? and copyable?.
|
|
(defn count-of [s [$t] x $t] i32
|
|
{:where (equal? $t)}
|
|
(let [n 0]
|
|
(dotimes [i (len s)]
|
|
(when (= (at s i) x)
|
|
(set n (+ n 1))))
|
|
n))
|
|
|
|
(defn clamp-to [x $t lo $t hi $t] $t
|
|
{:where (ordered? $t)}
|
|
(min (max x lo) hi))
|
|
|
|
;; Two variables, and the second is determined by its own argument.
|
|
(defn fst [a $t b $u] $t
|
|
{:where [(copyable? $t) (copyable? $u)]}
|
|
(do b a))
|
|
|
|
;; println over a type variable is the one form the abstract pass defers to
|
|
;; the instantiation, because its legality is only decidable after
|
|
;; substituting. The structural printer is selected per copy.
|
|
(defn show [x $t] ()
|
|
{:where (copyable? $t)}
|
|
(println x))
|
|
|
|
(defn main [] ()
|
|
(println (ident 3))
|
|
(println (ident 4.5))
|
|
(println (ident true))
|
|
(println (ident 7))
|
|
|
|
(let [ns [5 3 9 1]
|
|
fs [2.5 0.5 1.5]]
|
|
(println (first-or (slice ns 0 4) -1))
|
|
(println (first-or (slice ns 0 0) -1))
|
|
(rotate! (slice ns 0 4))
|
|
(println (at ns 3))
|
|
|
|
(println (twice 21))
|
|
(println (twice 1.5))
|
|
(println (count-of (slice ns 0 4) 9))
|
|
(println (clamp-to 12 0 10))
|
|
(println (clamp-to 0.5 1.0 9.0))
|
|
(println (fst 8 true))
|
|
|
|
(show 3)
|
|
(show 4.5)
|
|
(show "text")
|
|
|
|
;; The collapsed prelude family, at both element types.
|
|
(sort! (slice ns 0 4))
|
|
(println (at ns 0))
|
|
(sort-by! (slice fs 0 3) (fn [a b] (> a b)))
|
|
(println (at fs 0))
|
|
(reverse! (slice ns 0 4))
|
|
(println (at ns 0))
|
|
(map! (slice ns 0 4) (fn [x] (* x 2)))
|
|
(println (reduce (slice ns 0 4) 0 (fn [a b] (+ a b))))
|
|
(match (min-of (slice ns 0 4)) (Some m) (println m) _ (println -1))
|
|
(match (max-of (slice fs 0 3)) (Some m) (println m) _ (println -1.0))
|
|
(match (index-of (slice ns 0 4) 18) (Some i) (println i) _ (println -1))
|
|
(let [a (arena-new 4096)
|
|
keep (filter (slice ns 0 4) (fn [x] (> x 5)))]
|
|
(println (len (as-slice keep)))
|
|
(free keep)
|
|
(free-all a))))
|