diff --git a/lib/haskell/conformance.sh b/lib/haskell/conformance.sh index e05a3552..dba69251 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) +PROGRAMS=(fib sieve quicksort nqueens calculator collatz palindrome maybe fizzbuzz anagram roman binary either primes zipwith matrix wordcount powers caesar) PASS_COUNTS=() FAIL_COUNTS=() diff --git a/lib/haskell/tests/program-caesar.sx b/lib/haskell/tests/program-caesar.sx new file mode 100644 index 00000000..c7536d7b --- /dev/null +++ b/lib/haskell/tests/program-caesar.sx @@ -0,0 +1,80 @@ +;; caesar.hs — Caesar cipher. +;; Source: https://rosettacode.org/wiki/Caesar_cipher#Haskell (adapted). +;; +;; Exercises chr, ord, isUpper, isLower, mod, string pattern matching +;; (x:xs) over a String (which is now a [Char] string view), and map +;; from the Phase 7 string=[Char] foundation. + +(define + hk-prog-val + (fn + (src name) + (hk-deep-force (get (hk-eval-program (hk-core src)) name)))) + +(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)))) + +(define + hk-caesar-source + "shift n c = if isUpper c\n then chr (mod ((ord c) - 65 + n) 26 + 65)\n else if isLower c\n then chr (mod ((ord c) - 97 + n) 26 + 97)\n else chr c\n\ncaesarRec n [] = []\ncaesarRec n (x:xs) = shift n x : caesarRec n xs\n\ncaesarMap n s = map (shift n) s\n") + +(hk-test + "caesar.hs — caesarRec 3 \"ABC\" = DEF" + (hk-as-list + (hk-prog-val (str hk-caesar-source "r = caesarRec 3 \"ABC\"\n") "r")) + (list "D" "E" "F")) + +(hk-test + "caesar.hs — caesarRec 13 \"Hello\" = Uryyb" + (hk-as-list + (hk-prog-val (str hk-caesar-source "r = caesarRec 13 \"Hello\"\n") "r")) + (list "U" "r" "y" "y" "b")) + +(hk-test + "caesar.hs — caesarRec 1 \"AZ\" wraps to BA" + (hk-as-list + (hk-prog-val (str hk-caesar-source "r = caesarRec 1 \"AZ\"\n") "r")) + (list "B" "A")) + +(hk-test + "caesar.hs — caesarRec 0 \"World\" identity" + (hk-as-list + (hk-prog-val (str hk-caesar-source "r = caesarRec 0 \"World\"\n") "r")) + (list "W" "o" "r" "l" "d")) + +(hk-test + "caesar.hs — caesarRec preserves punctuation" + (hk-as-list + (hk-prog-val (str hk-caesar-source "r = caesarRec 3 \"Hi!\"\n") "r")) + (list "K" "l" "!")) + +(hk-test + "caesar.hs — caesarMap 3 \"abc\" via map" + (hk-as-list + (hk-prog-val (str hk-caesar-source "r = caesarMap 3 \"abc\"\n") "r")) + (list "d" "e" "f")) + +(hk-test + "caesar.hs — caesarMap 13 round-trips with caesarMap 13" + (hk-as-list + (hk-prog-val + (str + hk-caesar-source + "r = caesarMap 13 (foldr (\\c acc -> c : acc) [] (caesarMap 13 \"Hello\"))\n") + "r")) + (list "H" "e" "l" "l" "o")) + +(hk-test + "caesar.hs — caesarRec 25 \"AB\" = ZA" + (hk-as-list + (hk-prog-val (str hk-caesar-source "r = caesarRec 25 \"AB\"\n") "r")) + (list "Z" "A")) + +{: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 1aca6109..28ba1e20 100644 --- a/plans/haskell-completeness.md +++ b/plans/haskell-completeness.md @@ -284,6 +284,15 @@ No OCaml changes are needed. The view type is fully representable as an SX dict. _Newest first._ +**2026-05-06** — Phase 7 conformance (caesar.hs): +- New `lib/haskell/tests/program-caesar.sx` (8 tests). Caesar cipher exercising + `chr`, `ord`, `isUpper`, `isLower`, `mod`, `map`, and `(x:xs)` pattern matching + over native String values via the Phase 7 string-view path. Adapted from + https://rosettacode.org/wiki/Caesar_cipher#Haskell. +- `caesar` added to `PROGRAMS` in `lib/haskell/conformance.sh`. Suite isolated: + 8/8 passing. Note: `else chr c` in `shift` keeps the char-as-string output type + consistent with the alpha branches (pattern bind on a string view yields an int). + **2026-05-06** — Phase 7 complete (string-view O(1) head/tail + `++` native concat): - `runtime.sx`: added `hk-str?`, `hk-str-head`, `hk-str-tail`, `hk-str-null?`. String views are `{:hk-str buf :hk-off n}` dicts; native SX strings satisfy the