flan/test/programs/text.flan
Joseph Ferano a0278378ab Five randomness functions, and a draw wide enough to answer them
rand-int, rand, rand-bool, rand-int-range and rand-float-range, at the widths
the author ruled: a u64 draw and an f64 in [0, 1). rand-seed and rand-state
keep their names. The four old names are not names, and each is refused by the
one that is, with a call that compiles — in both the call and the bare-name
position, because a Lisp-1 makes the second a real thing to write.

The generator's step is untouched, so a seed means what it meant. Its output
function is not: PCG-XSH-RR folded the state to 32 bits, and no honest u64 or
53-bit f64 comes out of 32 bits without a second step. PCG-RXS-M-XS 64 answers
64 from the same one, so all five still cost exactly one draw and a seeded run
is reproducible. The price, written where it lives: the permutation is a
bijection of the state, which is what 64 output bits from 64 state bits costs.

The sequence is therefore a different one, and programs/rand.flan pins it —
reproducibility across the five, the single-draw cost of each, the half-open
boundaries, and rand-bool's count over a thousand flips.

sand.flan is not touched. It calls rand-f32, so the cases that compile or
re-evaluate it skip themselves on the fixture rather than on a comment: fix
its two calls and every one of them runs again. Its hash is the old
generator's grid and gets re-taken then.
2026-09-21 10:57:18 +07:00

84 lines
3.7 KiB
Plaintext

;;;; The prelude's byte predicates, parse-i64, and the two number helpers.
;;;;
;;;; The cases are chosen so a wrong implementation fails one: a prefix longer
;;;; than the string (which must answer false, not trap), the empty prefix and
;;;; the whole string as its own prefix, a prefix that matches at the wrong
;;;; end, and for parse-i64 every shape strtoll answers 0 for — "", "abc",
;;;; "12x", "-" — each of which a caller could not tell from a real 0.
(defn show-bool [b bool] ()
(print (if b "t" "f")))
(defn main [] i32
(show-bool (bytes=? (bytes-view "abc") (bytes-view "abc"))) ; t
(show-bool (bytes=? (bytes-view "abc") (bytes-view "abd"))) ; f same length
(show-bool (bytes=? (bytes-view "abc") (bytes-view "ab"))) ; f prefix, not equal
(show-bool (bytes=? (bytes-view "") (bytes-view ""))) ; t
(println "")
(show-bool (starts-with? (bytes-view "hello") (bytes-view "hel"))) ; t
(show-bool (starts-with? (bytes-view "hello") (bytes-view "llo"))) ; f matches the end
(show-bool (starts-with? (bytes-view "hi") (bytes-view "hiya"))) ; f longer, no trap
(show-bool (starts-with? (bytes-view "hello") (bytes-view ""))) ; t
(show-bool (starts-with? (bytes-view "hello") (bytes-view "hello"))) ; t
(println "")
(show-bool (ends-with? (bytes-view "hello") (bytes-view "llo"))) ; t
(show-bool (ends-with? (bytes-view "hello") (bytes-view "hel"))) ; f matches the start
(show-bool (ends-with? (bytes-view "hi") (bytes-view "hiya"))) ; f longer, no trap
(show-bool (ends-with? (bytes-view "hello") (bytes-view ""))) ; t
(show-bool (ends-with? (bytes-view "hello") (bytes-view "hello"))) ; t
(println "")
;; First occurrence, and None for a byte that is not there.
(print (match (index-of (bytes-view "banana") \a) (Some i) i None -1))
(print " ")
(print (match (index-of (bytes-view "banana") \z) (Some i) i None -1))
(print " ")
(print (match (index-of (bytes-view "") \a) (Some i) i None -1))
(println "")
;; Accepted.
(print (match (parse-i64 (bytes-view "0")) (Some v) v None -999)) (print " ")
(print (match (parse-i64 (bytes-view "42")) (Some v) v None -999)) (print " ")
(print (match (parse-i64 (bytes-view "-42")) (Some v) v None -999)) (print " ")
(print (match (parse-i64 (bytes-view "+7")) (Some v) v None -999)) (print " ")
(print (match (parse-i64 (bytes-view "9007199254740993")) (Some v) v None -999))
(println "")
;; Refused. Each of these is a 0 out of strtoll, which is the point.
(print (match (parse-i64 (bytes-view "")) (Some v) v None -999)) (print " ")
(print (match (parse-i64 (bytes-view "abc")) (Some v) v None -999)) (print " ")
(print (match (parse-i64 (bytes-view "12x")) (Some v) v None -999)) (print " ")
(print (match (parse-i64 (bytes-view "-")) (Some v) v None -999)) (print " ")
(print (match (parse-i64 (bytes-view " 1")) (Some v) v None -999))
(println "")
(print (sign-f32 3.5)) (print " ")
(print (sign-f32 -3.5)) (print " ")
(print (sign-f32 0.0))
(println "")
;; t = 1.0 must return b exactly, which a + t*(b - a) does not always do.
(print (lerp 0.0 10.0 0.0)) (print " ")
(print (lerp 0.0 10.0 0.25)) (print " ")
(print (lerp 0.0 10.0 1.0)) (print " ")
(print (lerp 2.0 -2.0 0.5))
(println "")
;; The RNG ranges, off a fixed seed, so the numbers are the sequence and not
;; just "something in range". An empty range answers lo and must not divide.
(rand-seed 7)
(dotimes [i 5]
(when (> i 0) (print " "))
(print (rand-int-range 10 20)))
(println "")
(print (rand-int-range 5 5)) (print " ")
(print (rand-int-range 5 -5))
(println "")
(rand-seed 7)
(dotimes [i 3]
(when (> i 0) (print " "))
(print (rand-float-range 0.0 1.0)))
(println "")
0)