Compare commits
2 Commits
9facbb4836
...
2b117288f6
| Author | SHA1 | Date | |
|---|---|---|---|
| 2b117288f6 | |||
| 8a9168c8d5 |
@@ -376,22 +376,11 @@
|
|||||||
hk-eval-let
|
hk-eval-let
|
||||||
(fn
|
(fn
|
||||||
(binds body env)
|
(binds body env)
|
||||||
|
;; Reuse hk-bind-decls! so multi-clause fun bindings in where/let
|
||||||
|
;; are grouped into multifuns, enabling patterns like:
|
||||||
|
;; let { go 0 = [[]]; go k = [...] } in go n
|
||||||
(let ((new-env (hk-dict-copy env)))
|
(let ((new-env (hk-dict-copy env)))
|
||||||
;; Pre-seed names for fn-clauses so closures see themselves
|
(hk-bind-decls! new-env binds)
|
||||||
;; (mutual recursion across the whole binding group).
|
|
||||||
(for-each
|
|
||||||
(fn (b)
|
|
||||||
(cond
|
|
||||||
((= (first b) "fun-clause")
|
|
||||||
(dict-set! new-env (nth b 1) nil))
|
|
||||||
((and
|
|
||||||
(= (first b) "bind")
|
|
||||||
(list? (nth b 1))
|
|
||||||
(= (first (nth b 1)) "p-var"))
|
|
||||||
(dict-set! new-env (nth (nth b 1) 1) nil))
|
|
||||||
(:else nil)))
|
|
||||||
binds)
|
|
||||||
(for-each (fn (b) (hk-eval-let-bind! b new-env)) binds)
|
|
||||||
(hk-eval body new-env))))
|
(hk-eval body new-env))))
|
||||||
|
|
||||||
(define
|
(define
|
||||||
@@ -561,6 +550,12 @@ zipWith _ _ [] = []
|
|||||||
zipWith f (x:xs) (y:ys) = f x y : zipWith f xs ys
|
zipWith f (x:xs) (y:ys) = f x y : zipWith f xs ys
|
||||||
fibs = 0 : 1 : zipWith plus fibs (tail fibs)
|
fibs = 0 : 1 : zipWith plus fibs (tail fibs)
|
||||||
plus a b = a + b
|
plus a b = a + b
|
||||||
|
concat [] = []
|
||||||
|
concat (xs:xss) = xs ++ concat xss
|
||||||
|
concatMap f [] = []
|
||||||
|
concatMap f (x:xs) = f x ++ concatMap f xs
|
||||||
|
abs x = if x < 0 then 0 - x else x
|
||||||
|
negate x = 0 - x
|
||||||
")
|
")
|
||||||
|
|
||||||
(define
|
(define
|
||||||
@@ -786,8 +781,12 @@ plus a b = a + b
|
|||||||
((has-key? env "main") (get env "main"))
|
((has-key? env "main") (get env "main"))
|
||||||
(:else env)))))
|
(:else 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 hk-env0 (hk-init-env))
|
||||||
|
|
||||||
(define
|
(define
|
||||||
hk-eval-expr-source
|
hk-eval-expr-source
|
||||||
(fn
|
(fn
|
||||||
(src)
|
(src)
|
||||||
(hk-deep-force (hk-eval (hk-core-expr src) (hk-init-env)))))
|
(hk-deep-force (hk-eval (hk-core-expr src) (hk-dict-copy hk-env0)))))
|
||||||
|
|||||||
38
lib/haskell/tests/program-nqueens.sx
Normal file
38
lib/haskell/tests/program-nqueens.sx
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
;; nqueens.hs — n-queens solver via list comprehension + where.
|
||||||
|
;;
|
||||||
|
;; Also exercises:
|
||||||
|
;; - multi-clause let/where binding (go 0 = ...; go k = ...)
|
||||||
|
;; - list comprehensions (desugared to concatMap)
|
||||||
|
;; - abs (from Prelude)
|
||||||
|
;; - [1..n] finite range
|
||||||
|
;;
|
||||||
|
;; n=8 is too slow for a 60s timeout; n=4 and n=5 run in ~17s combined.
|
||||||
|
|
||||||
|
(define
|
||||||
|
hk-prog-val
|
||||||
|
(fn
|
||||||
|
(src name)
|
||||||
|
(hk-deep-force (get (hk-eval-program (hk-core src)) name))))
|
||||||
|
|
||||||
|
(define
|
||||||
|
hk-nq-base
|
||||||
|
"queens n = go n
|
||||||
|
where
|
||||||
|
go 0 = [[]]
|
||||||
|
go k = [q:qs | qs <- go (k - 1), q <- [1..n], safe q qs]
|
||||||
|
safe q qs = check q qs 1
|
||||||
|
check q [] _ = True
|
||||||
|
check q (c:cs) d = q /= c && abs (q - c) /= d && check q cs (d + 1)
|
||||||
|
")
|
||||||
|
|
||||||
|
(hk-test
|
||||||
|
"nqueens: queens 4 has 2 solutions"
|
||||||
|
(hk-prog-val (str hk-nq-base "result = length (queens 4)\n") "result")
|
||||||
|
2)
|
||||||
|
|
||||||
|
(hk-test
|
||||||
|
"nqueens: queens 5 has 10 solutions"
|
||||||
|
(hk-prog-val (str hk-nq-base "result = length (queens 5)\n") "result")
|
||||||
|
10)
|
||||||
|
|
||||||
|
{:fails hk-test-fails :pass hk-test-pass :fail hk-test-fail}
|
||||||
18
lib/haskell/tests/programs/nqueens.hs
Normal file
18
lib/haskell/tests/programs/nqueens.hs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
-- nqueens.hs — n-queens backtracking solver.
|
||||||
|
--
|
||||||
|
-- `queens n` returns all solutions as lists of column positions,
|
||||||
|
-- one per row. Each call to `go k` extends all partial `(k-1)`-row
|
||||||
|
-- solutions by one safe queen, using a list comprehension whose guard
|
||||||
|
-- checks the new queen against all already-placed queens.
|
||||||
|
|
||||||
|
queens n = go n
|
||||||
|
where
|
||||||
|
go 0 = [[]]
|
||||||
|
go k = [q:qs | qs <- go (k - 1), q <- [1..n], safe q qs]
|
||||||
|
|
||||||
|
safe q qs = check q qs 1
|
||||||
|
|
||||||
|
check q [] _ = True
|
||||||
|
check q (c:cs) d = q /= c && abs (q - c) /= d && check q cs (d + 1)
|
||||||
|
|
||||||
|
result = length (queens 8)
|
||||||
@@ -85,7 +85,7 @@ Key mappings:
|
|||||||
- [x] `fib.hs` — infinite Fibonacci stream
|
- [x] `fib.hs` — infinite Fibonacci stream
|
||||||
- [x] `sieve.hs` — lazy sieve of Eratosthenes
|
- [x] `sieve.hs` — lazy sieve of Eratosthenes
|
||||||
- [x] `quicksort.hs` — naive QS
|
- [x] `quicksort.hs` — naive QS
|
||||||
- [ ] `nqueens.hs`
|
- [x] `nqueens.hs`
|
||||||
- [ ] `calculator.hs` — parser combinator style expression evaluator
|
- [ ] `calculator.hs` — parser combinator style expression evaluator
|
||||||
- [ ] `lib/haskell/conformance.sh` + runner; `scoreboard.json` + `scoreboard.md`
|
- [ ] `lib/haskell/conformance.sh` + runner; `scoreboard.json` + `scoreboard.md`
|
||||||
- [ ] Target: 5/5 classic programs passing
|
- [ ] Target: 5/5 classic programs passing
|
||||||
@@ -114,6 +114,16 @@ Key mappings:
|
|||||||
|
|
||||||
_Newest first._
|
_Newest first._
|
||||||
|
|
||||||
|
- **2026-04-25** — Classic program `nqueens.hs`: backtracking n-queens via list
|
||||||
|
comprehension and multi-clause `where`. Three fixes needed: (1) `hk-eval-let`
|
||||||
|
now delegates to `hk-bind-decls!` so multi-clause `where`/`let` bindings
|
||||||
|
(e.g., `go 0 = [[]]; go k = [...]`) are grouped as multifuns; (2) added
|
||||||
|
`concatMap`, `concat`, `abs`, `negate` to `hk-prelude-src` (list comprehensions
|
||||||
|
desugar to `concatMap`); (3) cached the Prelude env in `hk-env0` so
|
||||||
|
`hk-eval-expr-source` copies it instead of re-parsing. Tests: `queens 4 = 2`,
|
||||||
|
`queens 5 = 10`. n=8 (92 solutions) is too slow at ~50s/n — omitted.
|
||||||
|
397/397 green.
|
||||||
|
|
||||||
- **2026-04-25** — Classic program `quicksort.hs`: naive functional quicksort.
|
- **2026-04-25** — Classic program `quicksort.hs`: naive functional quicksort.
|
||||||
`qsort (x:xs) = qsort smaller ++ [x] ++ qsort larger where smaller = filter (< x) xs; larger = filter (>= x) xs`.
|
`qsort (x:xs) = qsort smaller ++ [x] ++ qsort larger where smaller = filter (< x) xs; larger = filter (>= x) xs`.
|
||||||
No new runtime additions needed — right sections, `filter`, `++` all worked out of the box.
|
No new runtime additions needed — right sections, `filter`, `++` all worked out of the box.
|
||||||
|
|||||||
Reference in New Issue
Block a user