haskell: Phase 8 audit — hk-show-val matches Haskell 98 (precedence-based parens, no-space separators)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 50s

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-06 22:27:30 +00:00
parent 685fcd11d5
commit 80d6507e57
4 changed files with 47 additions and 28 deletions

View File

@@ -584,13 +584,14 @@
result)))) result))))
(define (define
hk-show-val hk-show-prec
(fn (fn
(v) (v p)
(let (let
((fv (hk-force v))) ((fv (hk-force v)))
(cond (cond
((= (type-of fv) "number") (str fv)) ((= (type-of fv) "number")
(if (and (< fv 0) (>= p 11)) (str "(" fv ")") (str fv)))
((= (type-of fv) "string") (str "\"" fv "\"")) ((= (type-of fv) "string") (str "\"" fv "\""))
((= (type-of fv) "boolean") (if fv "True" "False")) ((= (type-of fv) "boolean") (if fv "True" "False"))
((not (list? fv)) (str fv)) ((not (list? fv)) (str fv))
@@ -599,9 +600,15 @@
((= (first fv) ":") ((= (first fv) ":")
(let (let
((elems (hk-collect-hk-list fv))) ((elems (hk-collect-hk-list fv)))
(str "[" (hk-join-strs (map hk-show-val elems) ", ") "]"))) (str
"["
(hk-join-strs (map (fn (e) (hk-show-prec e 0)) elems) ",")
"]")))
((= (first fv) "Tuple") ((= (first fv) "Tuple")
(str "(" (hk-join-strs (map hk-show-val (rest fv)) ", ") ")")) (str
"("
(hk-join-strs (map (fn (e) (hk-show-prec e 0)) (rest fv)) ",")
")"))
((= (first fv) "()") "()") ((= (first fv) "()") "()")
(:else (:else
(let (let
@@ -609,14 +616,15 @@
(if (if
(empty? args) (empty? args)
cname cname
(str (let
"(" ((s (str cname " " (hk-join-strs (map (fn (a) (hk-show-prec a 11)) args) " "))))
cname (if (>= p 11) (str "(" s ")") s)))))))))
" "
(hk-join-strs (map hk-show-val args) " ")
")"))))))))
;; ── Source-level convenience ──────────────────────────────── ;; ── Source-level convenience ────────────────────────────────
(define hk-show-val (fn (v) (hk-show-prec v 0)))
;; Eagerly build the Prelude env once at load time; each call to
;; hk-eval-expr-source copies it instead of re-parsing the whole Prelude.
(define (define
hk-init-env hk-init-env
(fn (fn
@@ -997,8 +1005,6 @@
1)) 1))
env))))) env)))))
;; Eagerly build the Prelude env once at load time; each call to
;; hk-eval-expr-source copies it instead of re-parsing the whole Prelude.
(define (define
hk-bind-decls! hk-bind-decls!
(fn (fn

View File

@@ -12,14 +12,14 @@
"deriving Show: constructor with arg" "deriving Show: constructor with arg"
(hk-deep-force (hk-deep-force
(hk-run "data Wrapper = Wrap Int deriving (Show)\nmain = show (Wrap 42)")) (hk-run "data Wrapper = Wrap Int deriving (Show)\nmain = show (Wrap 42)"))
"(Wrap 42)") "Wrap 42")
(hk-test (hk-test
"deriving Show: nested constructors" "deriving Show: nested constructors"
(hk-deep-force (hk-deep-force
(hk-run (hk-run
"data Tree = Leaf | Node Int Tree Tree deriving (Show)\nmain = show (Node 1 Leaf Leaf)")) "data Tree = Leaf | Node Int Tree Tree deriving (Show)\nmain = show (Node 1 Leaf Leaf)"))
"(Node 1 Leaf Leaf)") "Node 1 Leaf Leaf")
(hk-test (hk-test
"deriving Show: second constructor" "deriving Show: second constructor"
@@ -61,11 +61,11 @@
;; ─── combined Eq + Show ─────────────────────────────────────────────────────── ;; ─── combined Eq + Show ───────────────────────────────────────────────────────
(hk-test (hk-test
"deriving Eq Show: combined in parens" "deriving Eq Show: combined"
(hk-deep-force (hk-deep-force
(hk-run (hk-run
"data Shape = Circle Int | Square Int deriving (Eq, Show)\nmain = show (Circle 5)")) "data Shape = Circle Int | Square Int deriving (Eq, Show)\nmain = show (Circle 5)"))
"(Circle 5)") "Circle 5")
(hk-test (hk-test
"deriving Eq Show: eq on constructor with arg" "deriving Eq Show: eq on constructor with arg"

View File

@@ -37,11 +37,11 @@
(hk-ts "show neg" "negate 7" "-7") (hk-ts "show neg" "negate 7" "-7")
(hk-ts "show bool T" "True" "True") (hk-ts "show bool T" "True" "True")
(hk-ts "show bool F" "False" "False") (hk-ts "show bool F" "False" "False")
(hk-ts "show list" "[1,2,3]" "[1, 2, 3]") (hk-ts "show list" "[1,2,3]" "[1,2,3]")
(hk-ts "show Just" "Just 5" "(Just 5)") (hk-ts "show Just" "Just 5" "Just 5")
(hk-ts "show Nothing" "Nothing" "Nothing") (hk-ts "show Nothing" "Nothing" "Nothing")
(hk-ts "show LT" "LT" "LT") (hk-ts "show LT" "LT" "LT")
(hk-ts "show tuple" "(1, True)" "(1, True)") (hk-ts "show tuple" "(1, True)" "(1,True)")
;; ── Num extras ─────────────────────────────────────────────── ;; ── Num extras ───────────────────────────────────────────────
(hk-test "signum pos" (hk-deep-force (hk-run "main = signum 5")) 1) (hk-test "signum pos" (hk-deep-force (hk-run "main = signum 5")) 1)
@@ -59,13 +59,13 @@
(hk-test (hk-test
"foldr cons" "foldr cons"
(hk-deep-force (hk-run "main = show (foldr (:) [] [1,2,3])")) (hk-deep-force (hk-run "main = show (foldr (:) [] [1,2,3])"))
"[1, 2, 3]") "[1,2,3]")
;; ── List ops ───────────────────────────────────────────────── ;; ── List ops ─────────────────────────────────────────────────
(hk-test (hk-test
"reverse" "reverse"
(hk-deep-force (hk-run "main = show (reverse [1,2,3])")) (hk-deep-force (hk-run "main = show (reverse [1,2,3])"))
"[3, 2, 1]") "[3,2,1]")
(hk-test "null []" (hk-deep-force (hk-run "main = null []")) (list "True")) (hk-test "null []" (hk-deep-force (hk-run "main = null []")) (list "True"))
(hk-test (hk-test
"null xs" "null xs"
@@ -82,7 +82,7 @@
(hk-test (hk-test
"zip" "zip"
(hk-deep-force (hk-run "main = show (zip [1,2] [3,4])")) (hk-deep-force (hk-run "main = show (zip [1,2] [3,4])"))
"[(1, 3), (2, 4)]") "[(1,3),(2,4)]")
(hk-test "sum" (hk-deep-force (hk-run "main = sum [1,2,3,4,5]")) 15) (hk-test "sum" (hk-deep-force (hk-run "main = sum [1,2,3,4,5]")) 15)
(hk-test "product" (hk-deep-force (hk-run "main = product [1,2,3,4]")) 24) (hk-test "product" (hk-deep-force (hk-run "main = product [1,2,3,4]")) 24)
(hk-test "maximum" (hk-deep-force (hk-run "main = maximum [3,1,9,2]")) 9) (hk-test "maximum" (hk-deep-force (hk-run "main = maximum [3,1,9,2]")) 9)
@@ -112,7 +112,7 @@
(hk-test (hk-test
"fmap list" "fmap list"
(hk-deep-force (hk-run "main = show (fmap (+1) [1,2,3])")) (hk-deep-force (hk-run "main = show (fmap (+1) [1,2,3])"))
"[2, 3, 4]") "[2,3,4]")
;; ── Monad / Applicative ────────────────────────────────────── ;; ── Monad / Applicative ──────────────────────────────────────
(hk-test "return" (hk-deep-force (hk-run "main = return 7")) (list "IO" 7)) (hk-test "return" (hk-deep-force (hk-run "main = return 7")) (list "IO" 7))
@@ -134,7 +134,7 @@
(hk-test (hk-test
"lookup hit" "lookup hit"
(hk-deep-force (hk-run "main = show (lookup 2 [(1,10),(2,20)])")) (hk-deep-force (hk-run "main = show (lookup 2 [(1,10),(2,20)])"))
"(Just 20)") "Just 20")
(hk-test (hk-test
"lookup miss" "lookup miss"
(hk-deep-force (hk-run "main = show (lookup 9 [(1,10)])")) (hk-deep-force (hk-run "main = show (lookup 9 [(1,10)])"))

View File

@@ -97,9 +97,11 @@ No OCaml changes are needed. The view type is fully representable as an SX dict.
### Phase 8 — `show` for arbitrary types ### Phase 8 — `show` for arbitrary types
- [ ] Audit `hk-show-val` in `runtime.sx` — ensure output format matches - [x] Audit `hk-show-val` in `runtime.sx` — ensure output format matches
Haskell 98: `"Just 3"`, `"[1,2,3]"`, `"(True,False)"`, `"'a'"` (Char shows Haskell 98: `"Just 3"`, `"[1,2,3]"`, `"(True,False)"`, `"\"hello\""` (String
with single-quotes), `"\"hello\""` (String shows with escaped double-quotes). shows with escaped double-quotes). _Deferred:_ `"'a'"` Char single-quotes
(needs Char tagging — currently Char = Int by representation, ambiguous in
show); `\n`/`\t` escape inside Strings.
- [ ] `show` Prelude binding calls `hk-show-val`; `print x = putStrLn (show x)`. - [ ] `show` Prelude binding calls `hk-show-val`; `print x = putStrLn (show x)`.
- [ ] `deriving Show` auto-generates proper show for record-style and - [ ] `deriving Show` auto-generates proper show for record-style and
multi-constructor ADTs. Nested application arguments wrapped in parens: multi-constructor ADTs. Nested application arguments wrapped in parens:
@@ -284,6 +286,17 @@ No OCaml changes are needed. The view type is fully representable as an SX dict.
_Newest first._ _Newest first._
**2026-05-06** — Phase 8 audit: `hk-show-val` matches Haskell 98 format:
- `eval.sx`: introduced `hk-show-prec v p` with precedence-based parens.
Top-level `show (Just 3)` = `"Just 3"` (no parens); nested `show (Just (Just 3))`
= `"Just (Just 3)"` (inner wrapped because called with prec ≥ 11). Negative
ints wrapped in parens at high prec for `show (Just (negate 1))` correctness.
- List/tuple separators changed from `", "` to `","` to match GHC.
- `hk-show-val` is now a thin shim: `(hk-show-prec v 0)`.
- Updated `tests/deriving.sx` (3 tests) and `tests/stdlib.sx` (7 tests) to the
new format. `Char` single-quote output and string escape for `\n`/`\t`
deferred — Char = Int representation prevents disambiguation in show.
**2026-05-06** — Phase 7 conformance complete (runlength-str.hs) + `++` thunk fix: **2026-05-06** — Phase 7 conformance complete (runlength-str.hs) + `++` thunk fix:
- New `lib/haskell/tests/program-runlength-str.sx` (9 tests). Exercises `(x:xs)` - New `lib/haskell/tests/program-runlength-str.sx` (9 tests). Exercises `(x:xs)`
pattern matching over Strings, `span` over a string view, tuple `(Int, Char)` pattern matching over Strings, `span` over a string view, tuple `(Int, Char)`