From 2d373da06be0fc014fda9462055c3050ce0a275e Mon Sep 17 00:00:00 2001 From: giles Date: Thu, 7 May 2026 06:44:45 +0000 Subject: [PATCH] =?UTF-8?q?haskell:=20Phase=2010=20=E2=80=94=20fromIntegra?= =?UTF-8?q?l=20verified=20as=20prelude=20identity=20(+4=20tests,=2014/14)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- lib/haskell/tests/numerics.sx | 30 ++++++++++++++++++++++++++++++ plans/haskell-completeness.md | 12 ++++++++++-- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/lib/haskell/tests/numerics.sx b/lib/haskell/tests/numerics.sx index 23808964..f8334681 100644 --- a/lib/haskell/tests/numerics.sx +++ b/lib/haskell/tests/numerics.sx @@ -13,6 +13,16 @@ ;; we don't yet support arbitrary-precision Integer. Documented; unbounded ;; Integer is out of scope for Phase 10 — see Phase 11+ if it becomes needed. +(define + hk-as-list + (fn + (xs) + (cond + ((and (list? xs) (= (first xs) "[]")) (list)) + ((and (list? xs) (= (first xs) ":")) + (cons (nth xs 1) (hk-as-list (nth xs 2)))) + (:else xs)))) + (hk-test "factorial 10 = 3628800 (small, exact)" (hk-deep-force @@ -68,4 +78,24 @@ (hk-deep-force (hk-run "main = div 1000000000000000000 1000000000")) 1000000000) +(hk-test + "fromIntegral 42 = 42 (identity in our runtime)" + (hk-deep-force (hk-run "main = fromIntegral 42")) + 42) + +(hk-test + "fromIntegral preserves negative" + (hk-deep-force (hk-run "main = fromIntegral (negate 7)")) + -7) + +(hk-test + "fromIntegral round-trips through arithmetic" + (hk-deep-force (hk-run "main = fromIntegral 5 + fromIntegral 3")) + 8) + +(hk-test + "fromIntegral in a program (mixing with map)" + (hk-as-list (hk-deep-force (hk-run "main = map fromIntegral [1,2,3]"))) + (list 1 2 3)) + {:fails hk-test-fails :pass hk-test-pass :fail hk-test-fail} diff --git a/plans/haskell-completeness.md b/plans/haskell-completeness.md index 360f6b21..d7b42826 100644 --- a/plans/haskell-completeness.md +++ b/plans/haskell-completeness.md @@ -148,9 +148,10 @@ No OCaml changes are needed. The view type is fully representable as an SX dict. note limit in a comment if there is one. _Verified; documented practical limit of 2^53 (≈ 9e15) due to Haskell tokenizer parsing larger int literals as floats. Raw SX is exact to ±2^62. See header comment in `numerics.sx`._ -- [ ] `fromIntegral :: (Integral a, Num b) => a -> b` — identity in our runtime +- [x] `fromIntegral :: (Integral a, Num b) => a -> b` — identity in our runtime (all numbers share one SX type); register as a builtin no-op with the correct - typeclass signature. + typeclass signature. _Already in `hk-prelude-src` as `fromIntegral x = x`; + verified with new tests in `numerics.sx`._ - [ ] `toInteger`, `fromInteger` — same treatment. - [ ] Float/Double literals round-trip through `hk-show-val`: `show 3.14 = "3.14"`, `show 1.0e10 = "1.0e10"`. @@ -295,6 +296,13 @@ No OCaml changes are needed. The view type is fully representable as an SX dict. _Newest first._ +**2026-05-07** — Phase 10 `fromIntegral` verified (already an identity in prelude): +- Pre-existing `fromIntegral x = x` line in `hk-prelude-src` was already + correct — all numbers share one SX type, so the identity implementation is + exactly what the plan asked for. Added 4 tests in `numerics.sx` covering: + positive int, negative int, mixed-arithmetic, and `map fromIntegral [1,2,3]`. + Suite is now 14/14. + **2026-05-07** — Phase 10 large-integer audit (numerics.sx 10/10): - Investigated SX number behavior in Haskell context. Findings: • Raw SX `*`, `+`, etc. on two ints stay exact up to ±2^62 (~4.6e18).