fieldtest: floats — 4 examples, 6 findings (1 bug, 1 friction, 1 spec_gap, 3 working)
This commit is contained in:
@@ -0,0 +1 @@
|
||||
{"defs":[{"body":{"cond":{"args":[{"name":"k","t":"var"},{"lit":{"kind":"int","value":0},"t":"lit"}],"fn":{"name":"==","t":"var"},"t":"app"},"else":{"args":[{"name":"n","t":"var"},{"args":[{"lit":{"bits":"3fe0000000000000","kind":"float"},"t":"lit"},{"args":[{"name":"x","t":"var"},{"args":[{"name":"n","t":"var"},{"name":"x","t":"var"}],"fn":{"name":"/","t":"var"},"t":"app"}],"fn":{"name":"+","t":"var"},"t":"app"}],"fn":{"name":"*","t":"var"},"t":"app"},{"args":[{"name":"k","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"-","t":"var"},"t":"app"}],"fn":{"name":"newton_iter","t":"var"},"t":"app","tail":true},"t":"if","then":{"name":"x","t":"var"}},"doc":"Recurse k times applying x' = 0.5 * (x + n/x).","kind":"fn","name":"newton_iter","params":["n","x","k"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Float"},{"k":"con","name":"Float"},{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Float"}}},{"body":{"args":[{"name":"n","t":"var"},{"name":"n","t":"var"},{"lit":{"kind":"int","value":20},"t":"lit"}],"fn":{"name":"newton_iter","t":"var"},"t":"app"},"doc":"20-step Newton iteration starting from x0 = n.","kind":"fn","name":"sqrt","params":["n"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Float"}],"ret":{"k":"con","name":"Float"}}},{"body":{"args":[{"args":[{"lit":{"bits":"4000000000000000","kind":"float"},"t":"lit"}],"fn":{"name":"sqrt","t":"var"},"t":"app"}],"op":"io/print_float","t":"do"},"kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"floats_1_newton_sqrt","schema":"ailang/v0"}
|
||||
@@ -0,0 +1,38 @@
|
||||
; Fieldtest — Floats milestone, axis 1: numerical computation.
|
||||
;
|
||||
; Newton's method for sqrt(N): x_{k+1} = 0.5 * (x_k + N / x_k).
|
||||
; Iterate a fixed 20 times — well past convergence for double-precision
|
||||
; from a starting guess of N (always positive). Prints the result of
|
||||
; sqrt(2.0). Expected stdout (one line): approximately 1.41421356...
|
||||
;
|
||||
; Exercises: Float literals, polymorphic +, *, /, recursion with
|
||||
; Float-typed accumulator, io/print_float.
|
||||
|
||||
(module floats_1_newton_sqrt
|
||||
|
||||
(fn newton_iter
|
||||
(doc "Recurse k times applying x' = 0.5 * (x + n/x).")
|
||||
(type
|
||||
(fn-type
|
||||
(params (con Float) (con Float) (con Int))
|
||||
(ret (con Float))))
|
||||
(params n x k)
|
||||
(body
|
||||
(if (app == k 0)
|
||||
x
|
||||
(tail-app newton_iter
|
||||
n
|
||||
(app * 0.5 (app + x (app / n x)))
|
||||
(app - k 1)))))
|
||||
|
||||
(fn sqrt
|
||||
(doc "20-step Newton iteration starting from x0 = n.")
|
||||
(type (fn-type (params (con Float)) (ret (con Float))))
|
||||
(params n)
|
||||
(body (app newton_iter n n 20)))
|
||||
|
||||
(fn main
|
||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||
(params)
|
||||
(body
|
||||
(do io/print_float (app sqrt 2.0)))))
|
||||
@@ -0,0 +1 @@
|
||||
{"defs":[{"ctors":[{"fields":[],"name":"Nil"},{"fields":[{"k":"con","name":"Int"},{"k":"con","name":"IntList"}],"name":"Cons"}],"kind":"type","name":"IntList"},{"body":{"arms":[{"body":{"name":"acc","t":"var"},"pat":{"ctor":"Nil","fields":[],"p":"ctor"}},{"body":{"args":[{"name":"t","t":"var"},{"args":[{"name":"acc","t":"var"},{"name":"h","t":"var"}],"fn":{"name":"+","t":"var"},"t":"app"}],"fn":{"name":"sum_acc","t":"var"},"t":"app","tail":true},"pat":{"ctor":"Cons","fields":[{"name":"h","p":"var"},{"name":"t","p":"var"}],"p":"ctor"}}],"scrutinee":{"name":"xs","t":"var"},"t":"match"},"doc":"Tail-recursive sum with accumulator.","kind":"fn","name":"sum_acc","params":["xs","acc"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"IntList"},{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Int"}}},{"body":{"arms":[{"body":{"name":"acc","t":"var"},"pat":{"ctor":"Nil","fields":[],"p":"ctor"}},{"body":{"args":[{"name":"t","t":"var"},{"args":[{"name":"acc","t":"var"},{"lit":{"kind":"int","value":1},"t":"lit"}],"fn":{"name":"+","t":"var"},"t":"app"}],"fn":{"name":"count_acc","t":"var"},"t":"app","tail":true},"pat":{"ctor":"Cons","fields":[{"p":"wild"},{"name":"t","p":"var"}],"p":"ctor"}}],"scrutinee":{"name":"xs","t":"var"},"t":"match"},"doc":"Tail-recursive length with accumulator.","kind":"fn","name":"count_acc","params":["xs","acc"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"IntList"},{"k":"con","name":"Int"}],"ret":{"k":"con","name":"Int"}}},{"body":{"args":[{"args":[{"args":[{"name":"xs","t":"var"},{"lit":{"kind":"int","value":0},"t":"lit"}],"fn":{"name":"sum_acc","t":"var"},"t":"app"}],"fn":{"name":"int_to_float","t":"var"},"t":"app"},{"args":[{"args":[{"name":"xs","t":"var"},{"lit":{"kind":"int","value":0},"t":"lit"}],"fn":{"name":"count_acc","t":"var"},"t":"app"}],"fn":{"name":"int_to_float","t":"var"},"t":"app"}],"fn":{"name":"/","t":"var"},"t":"app"},"doc":"Mean as Float = sum / count, both promoted via int_to_float.","kind":"fn","name":"mean","params":["xs"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"IntList"}],"ret":{"k":"con","name":"Float"}}},{"body":{"args":[{"args":[{"args":[{"lit":{"kind":"int","value":1},"t":"lit"},{"args":[{"lit":{"kind":"int","value":2},"t":"lit"},{"args":[{"lit":{"kind":"int","value":3},"t":"lit"},{"args":[{"lit":{"kind":"int","value":4},"t":"lit"},{"args":[{"lit":{"kind":"int","value":6},"t":"lit"},{"args":[],"ctor":"Nil","t":"ctor","type":"IntList"}],"ctor":"Cons","t":"ctor","type":"IntList"}],"ctor":"Cons","t":"ctor","type":"IntList"}],"ctor":"Cons","t":"ctor","type":"IntList"}],"ctor":"Cons","t":"ctor","type":"IntList"}],"ctor":"Cons","t":"ctor","type":"IntList"}],"fn":{"name":"mean","t":"var"},"t":"app"}],"op":"io/print_float","t":"do"},"kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"floats_2_average_int_list","schema":"ailang/v0"}
|
||||
@@ -0,0 +1,67 @@
|
||||
; Fieldtest — Floats milestone, axis 2: Int/Float interop.
|
||||
;
|
||||
; Compute the arithmetic mean of an Int list and print it as a Float.
|
||||
; Sum is Int (no overflow risk for the inputs we use); count is Int;
|
||||
; the divide must happen in Float space so we get a fractional result.
|
||||
;
|
||||
; This is the canonical task that exercises int_to_float at both
|
||||
; converted operands. The literal `2` cannot be shared with Float
|
||||
; arithmetic, so the natural shape is:
|
||||
; (/ (int_to_float sum) (int_to_float count))
|
||||
;
|
||||
; Inputs: [1, 2, 3, 4, 6]; sum=16, count=5; mean=3.2.
|
||||
; Expected stdout: 3.2
|
||||
|
||||
(module floats_2_average_int_list
|
||||
|
||||
(data IntList
|
||||
(ctor Nil)
|
||||
(ctor Cons (con Int) (con IntList)))
|
||||
|
||||
(fn sum_acc
|
||||
(doc "Tail-recursive sum with accumulator.")
|
||||
(type
|
||||
(fn-type
|
||||
(params (con IntList) (con Int))
|
||||
(ret (con Int))))
|
||||
(params xs acc)
|
||||
(body
|
||||
(match xs
|
||||
(case (pat-ctor Nil) acc)
|
||||
(case (pat-ctor Cons h t)
|
||||
(tail-app sum_acc t (app + acc h))))))
|
||||
|
||||
(fn count_acc
|
||||
(doc "Tail-recursive length with accumulator.")
|
||||
(type
|
||||
(fn-type
|
||||
(params (con IntList) (con Int))
|
||||
(ret (con Int))))
|
||||
(params xs acc)
|
||||
(body
|
||||
(match xs
|
||||
(case (pat-ctor Nil) acc)
|
||||
(case (pat-ctor Cons _ t)
|
||||
(tail-app count_acc t (app + acc 1))))))
|
||||
|
||||
(fn mean
|
||||
(doc "Mean as Float = sum / count, both promoted via int_to_float.")
|
||||
(type (fn-type (params (con IntList)) (ret (con Float))))
|
||||
(params xs)
|
||||
(body
|
||||
(app /
|
||||
(app int_to_float (app sum_acc xs 0))
|
||||
(app int_to_float (app count_acc xs 0)))))
|
||||
|
||||
(fn main
|
||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||
(params)
|
||||
(body
|
||||
(do io/print_float
|
||||
(app mean
|
||||
(term-ctor IntList Cons 1
|
||||
(term-ctor IntList Cons 2
|
||||
(term-ctor IntList Cons 3
|
||||
(term-ctor IntList Cons 4
|
||||
(term-ctor IntList Cons 6
|
||||
(term-ctor IntList Nil)))))))))))
|
||||
@@ -0,0 +1 @@
|
||||
{"defs":[{"body":{"cond":{"args":[{"name":"x","t":"var"}],"fn":{"name":"is_nan","t":"var"},"t":"app"},"else":{"cond":{"args":[{"name":"x","t":"var"},{"lit":{"bits":"7fe1ccf385ebc8a0","kind":"float"},"t":"lit"}],"fn":{"name":">","t":"var"},"t":"app"},"else":{"cond":{"args":[{"name":"x","t":"var"},{"lit":{"bits":"ffe1ccf385ebc8a0","kind":"float"},"t":"lit"}],"fn":{"name":"<","t":"var"},"t":"app"},"else":{"lit":{"kind":"int","value":1},"t":"lit"},"t":"if","then":{"lit":{"kind":"int","value":0},"t":"lit"}},"t":"if","then":{"lit":{"kind":"int","value":0},"t":"lit"}},"t":"if","then":{"lit":{"kind":"int","value":-1},"t":"lit"}},"doc":"-1=NaN, 0=infinite, 1=finite. Uses is_nan + abs > huge.","kind":"fn","name":"classify","params":["x"],"type":{"effects":[],"k":"fn","params":[{"k":"con","name":"Float"}],"ret":{"k":"con","name":"Int"}}},{"body":{"lhs":{"args":[{"args":[{"lit":{"bits":"4018000000000000","kind":"float"},"t":"lit"},{"lit":{"bits":"4008000000000000","kind":"float"},"t":"lit"}],"fn":{"name":"/","t":"var"},"t":"app"}],"op":"io/print_float","t":"do"},"rhs":{"lhs":{"args":[{"args":[{"args":[{"lit":{"bits":"4018000000000000","kind":"float"},"t":"lit"},{"lit":{"bits":"4008000000000000","kind":"float"},"t":"lit"}],"fn":{"name":"/","t":"var"},"t":"app"}],"fn":{"name":"classify","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"rhs":{"lhs":{"args":[{"args":[{"lit":{"bits":"3ff0000000000000","kind":"float"},"t":"lit"},{"lit":{"bits":"0000000000000000","kind":"float"},"t":"lit"}],"fn":{"name":"/","t":"var"},"t":"app"}],"op":"io/print_float","t":"do"},"rhs":{"lhs":{"args":[{"args":[{"args":[{"lit":{"bits":"3ff0000000000000","kind":"float"},"t":"lit"},{"lit":{"bits":"0000000000000000","kind":"float"},"t":"lit"}],"fn":{"name":"/","t":"var"},"t":"app"}],"fn":{"name":"classify","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"rhs":{"lhs":{"args":[{"args":[{"lit":{"bits":"0000000000000000","kind":"float"},"t":"lit"},{"lit":{"bits":"0000000000000000","kind":"float"},"t":"lit"}],"fn":{"name":"/","t":"var"},"t":"app"}],"op":"io/print_float","t":"do"},"rhs":{"args":[{"args":[{"args":[{"lit":{"bits":"0000000000000000","kind":"float"},"t":"lit"},{"lit":{"bits":"0000000000000000","kind":"float"},"t":"lit"}],"fn":{"name":"/","t":"var"},"t":"app"}],"fn":{"name":"classify","t":"var"},"t":"app"}],"op":"io/print_int","t":"do"},"t":"seq"},"t":"seq"},"t":"seq"},"t":"seq"},"t":"seq"},"kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"floats_3_safe_division","schema":"ailang/v0"}
|
||||
@@ -0,0 +1,55 @@
|
||||
; Fieldtest — Floats milestone, axis 3: NaN / Inf / is_nan handling.
|
||||
;
|
||||
; safe_div(a, b) returns a/b when b != 0; falls through to the IEEE
|
||||
; result otherwise. The fixture exercises four cases:
|
||||
; 1) 6.0 / 3.0 -> 2.0 (normal)
|
||||
; 2) 1.0 / 0.0 -> +inf (use is_nan to confirm finite-vs-NaN)
|
||||
; 3) 0.0 / 0.0 -> NaN (is_nan should report true)
|
||||
; 4) (- 1.0 1.0) / 0.0 -> NaN (subexpr drives same)
|
||||
;
|
||||
; classify(x) returns:
|
||||
; -1 if x is NaN
|
||||
; 0 if x is +inf or -inf (we test via x > <huge> / x < -<huge>)
|
||||
; 1 otherwise
|
||||
;
|
||||
; The subtle point: the IEEE-correct way to test for NaN is `is_nan`,
|
||||
; NOT `(== x x)` (which is false for NaN — but the LLM author who
|
||||
; reaches for `==` first will get the right answer by accident here,
|
||||
; only because the natural reading of the operator doesn't apply).
|
||||
; The DESIGN.md says explicitly to use `is_nan`.
|
||||
;
|
||||
; Expected stdout (one per line):
|
||||
; 2.0 ; 6/3
|
||||
; 1 ; classify(2.0) -> normal
|
||||
; inf ; 1/0
|
||||
; 0 ; classify(1/0) -> infinite
|
||||
; nan ; 0/0
|
||||
; -1 ; classify(0/0) -> NaN
|
||||
;
|
||||
; (`io/print_float` prints "%g\n", so inf prints as "inf", NaN as "nan".)
|
||||
|
||||
(module floats_3_safe_division
|
||||
|
||||
(fn classify
|
||||
(doc "-1=NaN, 0=infinite, 1=finite. Uses is_nan + abs > huge.")
|
||||
(type (fn-type (params (con Float)) (ret (con Int))))
|
||||
(params x)
|
||||
(body
|
||||
(if (app is_nan x)
|
||||
-1
|
||||
(if (app > x 1.0e308)
|
||||
0
|
||||
(if (app < x -1.0e308)
|
||||
0
|
||||
1)))))
|
||||
|
||||
(fn main
|
||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||
(params)
|
||||
(body
|
||||
(seq (do io/print_float (app / 6.0 3.0))
|
||||
(seq (do io/print_int (app classify (app / 6.0 3.0)))
|
||||
(seq (do io/print_float (app / 1.0 0.0))
|
||||
(seq (do io/print_int (app classify (app / 1.0 0.0)))
|
||||
(seq (do io/print_float (app / 0.0 0.0))
|
||||
(do io/print_int (app classify (app / 0.0 0.0)))))))))))
|
||||
@@ -0,0 +1 @@
|
||||
{"defs":[{"body":{"args":[{"args":[{"lit":{"bits":"40091eb851eb851f","kind":"float"},"t":"lit"}],"fn":{"name":"float_to_str","t":"var"},"t":"app"}],"op":"io/print_str","t":"do"},"kind":"fn","name":"main","params":[],"type":{"effects":["IO"],"k":"fn","params":[],"ret":{"k":"con","name":"Unit"}}}],"imports":[],"name":"floats_4_float_to_str_reach","schema":"ailang/v0"}
|
||||
@@ -0,0 +1,26 @@
|
||||
; Fieldtest — Floats milestone, axis 4: reach for float_to_str.
|
||||
;
|
||||
; Natural task: build a label like "result = <float>" by concatenating
|
||||
; a Str prefix with the float's text. The LLM-author who looks at
|
||||
; `ail builtins` sees `float_to_str : (Float) -> Str`, reaches for it,
|
||||
; and gets a codegen-deferred error per DESIGN.md §"Float semantics":
|
||||
;
|
||||
; `float_to_str` (Float → Str) is type-installed but codegen-
|
||||
; deferred to a follow-up milestone: ... Calling it typechecks but
|
||||
; produces a structured `CodegenError::Internal`.
|
||||
;
|
||||
; This fixture pins the reach-and-bounce. Expected: `ail check`
|
||||
; succeeds; `ail build` fails with a clear, structured codegen error
|
||||
; that names `float_to_str` and points at the missing runtime path.
|
||||
;
|
||||
; (No string-concat builtin exists either; we just print the result of
|
||||
; float_to_str directly via io/print_str. The first failure point is
|
||||
; codegen, before any concat would be needed.)
|
||||
|
||||
(module floats_4_float_to_str_reach
|
||||
|
||||
(fn main
|
||||
(type (fn-type (params) (ret (con Unit)) (effects IO)))
|
||||
(params)
|
||||
(body
|
||||
(do io/print_str (app float_to_str 3.14)))))
|
||||
Reference in New Issue
Block a user