flan/test/programs/fn-values.flan
Joseph Ferano dad725afe4 The prelude's per-type families collapse: 22 functions become 10, 27 become 16
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.
2026-09-13 14:49:11 +07:00

89 lines
3.2 KiB
Plaintext

;; Function values, the non-escaping kind: a code address and no environment
;; beside it. Capture does not exist, so nothing here can outlive anything.
;;
;; This is a Lisp-1 — one top-level namespace, enforced — so a bare function
;; name *is* the function and there is no #' to write.
(defn double [x i32] i32 (* x 2))
(defn negate [x i32] i32 (- 0 x))
(defn square [x i32] i32 (* x x))
;; The shape map/filter/reduce want: the function arrives as a parameter, is
;; called, and is never stored.
(defn each! [xs [i32] f (Fn [i32] i32)] ()
(dotimes [i (len xs)]
(set (at xs i) (f (at xs i)))))
(defn fold [xs [i32] f (Fn [i32] i32)] i32
(let [t 0]
(dotimes [i (len xs)]
(set t (+ t (f (at xs i)))))
t))
;; A comparator, which is the other half of what was blocked: a sort that is
;; told the order rather than having it written in. Insertion sort, because the
;; point here is the parameter and not the algorithm.
(defn insertion-by! [xs [i32] before? (Fn [i32 i32] bool)] ()
(dotimes [i (len xs)]
(let [j i]
(while (and (> j 0) (before? (at xs j) (at xs (- j 1))))
(swap! xs j (- j 1))
(set j (- j 1))))))
(defn ascending [a i32 b i32] bool (< a b))
(defn descending [a i32 b i32] bool (> a b))
;; Returning one. A function value is a link-time constant with no environment,
;; so handing it back up is no different from handing it down.
(defn pick [up bool] (Fn [i32 i32] bool)
(if up ascending descending))
;; A function value calling another, and the transfer channel crossing an
;; indirect call: a callee reached by pointer signals exactly as one reached by
;; name, and the handler is established across the call.
(defstruct TooBig [n i32])
(defn checked [x i32] i32
(when (> x 100) (signal (TooBig {.n x})))
x)
(defvar seen i32)
;; A handler-bind and an fn literal in *one* function, which is the case that
;; would catch the two lifted-function name sequences sharing a counter: both
;; are lifted out of [handles] and both are numbered within it.
(defn handles [] ()
(handler-bind [(TooBig [c] (set seen (+ seen (.n c))))]
(let [xs [5 200 7 300]]
(println (fold (slice xs 0 4) checked))
(println (fold (slice xs 0 4) (fn [x] (min x 10))))))
(print "seen ") (print seen) (println ""))
(defn main [] i32
(let [xs [1 2 3 4]]
;; A name in value position, passed down.
(each! (slice xs 0 4) double)
(print (at xs 0)) (print " ") (print (at xs 3)) (println "")
;; 2 + 4 + 6 + 8 negated
(println (fold (slice xs 0 4) negate))
;; An fn literal, whose parameter types come from the position it is in.
(println (fold (slice xs 0 4) (fn [x] (+ x 1))))
;; A let binding of function type, called by the name it is bound to.
(let [f square]
(println (f 9))))
;; A comparator, and the same slice sorted both ways.
(let [ys [3 1 4 1 5 9 2 6]
s (slice ys 0 8)]
(insertion-by! s ascending)
(print (at s 0)) (print " ") (print (at s 7)) (println "")
(insertion-by! s descending)
(print (at s 0)) (print " ") (print (at s 7)) (println "")
;; A returned function value, and a computed head calling it.
(insertion-by! s (pick true))
(print (at s 0)) (println "")
(println ((pick false) 1 2)))
(handles)
0)