diff --git a/lib/haskell/conformance.sh b/lib/haskell/conformance.sh index 9fe3fe3d..ddd0a45c 100755 --- a/lib/haskell/conformance.sh +++ b/lib/haskell/conformance.sh @@ -20,7 +20,7 @@ if [ ! -x "$SX_SERVER" ]; then fi fi -PROGRAMS=(fib sieve quicksort nqueens calculator collatz palindrome maybe fizzbuzz anagram roman binary either primes zipwith matrix wordcount powers caesar runlength-str showadt showio partial statistics newton wordfreq mapgraph uniquewords setops shapes) +PROGRAMS=(fib sieve quicksort nqueens calculator collatz palindrome maybe fizzbuzz anagram roman binary either primes zipwith matrix wordcount powers caesar runlength-str showadt showio partial statistics newton wordfreq mapgraph uniquewords setops shapes person config) PASS_COUNTS=() FAIL_COUNTS=() diff --git a/lib/haskell/tests/program-config.sx b/lib/haskell/tests/program-config.sx new file mode 100644 index 00000000..b15841b8 --- /dev/null +++ b/lib/haskell/tests/program-config.sx @@ -0,0 +1,63 @@ +;; config.hs — multi-field config record; partial update; defaultConfig +;; constant. +;; +;; Exercises Phase 14: 4-field record, defaultConfig as a CAF, partial +;; updates that change one or two fields, accessors over derived configs. + +(define + hk-config-source + "data Config = Config { host :: String, port :: Int, retries :: Int, debug :: Bool } deriving (Show)\n\ndefaultConfig = Config { host = \"localhost\", port = 8080, retries = 3, debug = False }\n\ndevConfig = defaultConfig { debug = True }\nremoteConfig = defaultConfig { host = \"api.example.com\", port = 443 }\n") + +(hk-test + "config.hs — defaultConfig host" + (hk-deep-force (hk-run (str hk-config-source "main = host defaultConfig"))) + "localhost") + +(hk-test + "config.hs — defaultConfig port" + (hk-deep-force (hk-run (str hk-config-source "main = port defaultConfig"))) + 8080) + +(hk-test + "config.hs — defaultConfig retries" + (hk-deep-force + (hk-run (str hk-config-source "main = retries defaultConfig"))) + 3) + +(hk-test + "config.hs — devConfig flips debug" + (hk-deep-force (hk-run (str hk-config-source "main = debug devConfig"))) + (list "True")) + +(hk-test + "config.hs — devConfig preserves host" + (hk-deep-force (hk-run (str hk-config-source "main = host devConfig"))) + "localhost") + +(hk-test + "config.hs — devConfig preserves port" + (hk-deep-force (hk-run (str hk-config-source "main = port devConfig"))) + 8080) + +(hk-test + "config.hs — remoteConfig new host" + (hk-deep-force (hk-run (str hk-config-source "main = host remoteConfig"))) + "api.example.com") + +(hk-test + "config.hs — remoteConfig new port" + (hk-deep-force (hk-run (str hk-config-source "main = port remoteConfig"))) + 443) + +(hk-test + "config.hs — remoteConfig preserves retries" + (hk-deep-force + (hk-run (str hk-config-source "main = retries remoteConfig"))) + 3) + +(hk-test + "config.hs — remoteConfig preserves debug" + (hk-deep-force (hk-run (str hk-config-source "main = debug remoteConfig"))) + (list "False")) + +{:fails hk-test-fails :pass hk-test-pass :fail hk-test-fail} diff --git a/lib/haskell/tests/program-person.sx b/lib/haskell/tests/program-person.sx new file mode 100644 index 00000000..a295618e --- /dev/null +++ b/lib/haskell/tests/program-person.sx @@ -0,0 +1,51 @@ +;; person.hs — record type with accessors, update, deriving Show. +;; +;; Exercises Phase 14: data with record syntax, accessor functions, +;; record creation, record update, deriving Show on a record. + +(define + hk-person-source + "data Person = Person { name :: String, age :: Int } deriving (Show)\n\nalice = Person { name = \"alice\", age = 30 }\nbob = Person { name = \"bob\", age = 25 }\n\nbirthday p = p { age = age p + 1 }\n") + +(hk-test + "person.hs — alice's name" + (hk-deep-force (hk-run (str hk-person-source "main = name alice"))) + "alice") + +(hk-test + "person.hs — alice's age" + (hk-deep-force (hk-run (str hk-person-source "main = age alice"))) + 30) + +(hk-test + "person.hs — birthday adds one year" + (hk-deep-force + (hk-run (str hk-person-source "main = age (birthday alice)"))) + 31) + +(hk-test + "person.hs — birthday preserves name" + (hk-deep-force + (hk-run (str hk-person-source "main = name (birthday alice)"))) + "alice") + +(hk-test + "person.hs — show alice" + (hk-deep-force (hk-run (str hk-person-source "main = show alice"))) + "Person \"alice\" 30") + +(hk-test + "person.hs — bob has different name" + (hk-deep-force (hk-run (str hk-person-source "main = name bob"))) + "bob") + +(hk-test + "person.hs — pattern match in function" + (hk-deep-force + (hk-run + (str + hk-person-source + "greet (Person { name = n }) = \"Hi, \" ++ n\nmain = greet alice"))) + "Hi, alice") + +{: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 4d79afee..35283554 100644 --- a/plans/haskell-completeness.md +++ b/plans/haskell-completeness.md @@ -264,7 +264,7 @@ No OCaml changes are needed. The view type is fully representable as an SX dict. - [x] Tests in `lib/haskell/tests/records.sx` (14/14, plan ≥12: creation with reorder, accessors, single + two-field update, case-alt + fun-LHS record patterns, `deriving Show` on record types). -- [ ] Conformance programs: +- [x] Conformance programs: - `person.hs` — `data Person = Person { name :: String, age :: Int }` with accessors, update, `deriving Show`. - `config.hs` — multi-field config record; partial update; defaultConfig @@ -315,6 +315,16 @@ No OCaml changes are needed. The view type is fully representable as an SX dict. _Newest first._ +**2026-05-07** — Phase 14 conformance: person.hs (7/7) + config.hs (10/10) → Phase 14 complete: +- `program-person.sx`: classic Person record with `birthday p = p { age = age p + 1 }` + exercising the read-then-update idiom on a CAF instance, plus `deriving Show` + output. +- `program-config.sx`: 4-field Config record with defaultConfig CAF, two + derived configs via partial update (devConfig flips one Bool, remoteConfig + changes two String/Int fields). 10 tests covering both branches preserve + the unchanged fields. +- Both added to `PROGRAMS` in `conformance.sh`. Phase 14 fully complete. + **2026-05-07** — Phase 14 unit tests `tests/records.sx` (14/14): - Covers creation (with field reorder), accessors, single-field update, two-field update, case-alt + fun-LHS record patterns, and `deriving Show`