haskell: classic program fib.hs + source-order top-level binding (+2 tests, 388/388)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled
This commit is contained in:
@@ -677,16 +677,22 @@ plus a b = a + b
|
||||
hk-bind-decls!
|
||||
(fn
|
||||
(env decls)
|
||||
(let ((groups (dict)) (pat-binds (list)))
|
||||
;; Pass 1: collect fun-clause groups by name; collect pat-binds
|
||||
;; in source order. Pre-seed env so any name can already be
|
||||
;; looked up by closures built in pass 2.
|
||||
(let
|
||||
((groups (dict))
|
||||
(group-order (list))
|
||||
(pat-binds (list)))
|
||||
;; Pass 1: collect fun-clause groups by name; track first-seen
|
||||
;; order so pass 3 can evaluate 0-arity bodies in source order
|
||||
;; (forward references to other 0-arity definitions still need
|
||||
;; the earlier name to be bound first).
|
||||
(for-each
|
||||
(fn (d)
|
||||
(cond
|
||||
((= (first d) "fun-clause")
|
||||
(let
|
||||
((name (nth d 1)))
|
||||
(when (not (has-key? groups name))
|
||||
(append! group-order name))
|
||||
(dict-set!
|
||||
groups
|
||||
name
|
||||
@@ -703,8 +709,9 @@ plus a b = a + b
|
||||
(append! pat-binds d))
|
||||
(:else nil)))
|
||||
decls)
|
||||
;; Pass 2: install multifuns for arity > 0; mark 0-arity for
|
||||
;; pass 3. The mutable env means recursive references work.
|
||||
;; Pass 2: install multifuns (arity > 0) — order doesn't matter
|
||||
;; because they're closures; collect 0-arity names in source
|
||||
;; order for pass 3.
|
||||
(let ((zero-arity (list)))
|
||||
(for-each
|
||||
(fn (name)
|
||||
@@ -717,8 +724,11 @@ plus a b = a + b
|
||||
name
|
||||
(hk-mk-multifun arity clauses env)))
|
||||
(:else (append! zero-arity name))))))
|
||||
(keys groups))
|
||||
;; Pass 3: evaluate 0-arity bodies and pat-binds.
|
||||
group-order)
|
||||
;; Pass 3: evaluate 0-arity bodies and pat-binds in source
|
||||
;; order — forward references to a later 0-arity name will
|
||||
;; still see its placeholder (nil) and fail noisily, but the
|
||||
;; common case of a top-down program works.
|
||||
(for-each
|
||||
(fn (name)
|
||||
(let ((clauses (get groups name)))
|
||||
|
||||
45
lib/haskell/tests/program-fib.sx
Normal file
45
lib/haskell/tests/program-fib.sx
Normal file
@@ -0,0 +1,45 @@
|
||||
;; fib.hs — infinite Fibonacci stream classic program.
|
||||
;;
|
||||
;; The canonical artefact lives at lib/haskell/tests/programs/fib.hs.
|
||||
;; The source is mirrored here as an SX string because the evaluator
|
||||
;; doesn't have read-file in the default env. If you change one, keep
|
||||
;; the other in sync — there's a runner-level cross-check against the
|
||||
;; expected first-15 list.
|
||||
|
||||
(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-fib-source
|
||||
"zipPlus (x:xs) (y:ys) = x + y : zipPlus xs ys
|
||||
zipPlus _ _ = []
|
||||
myFibs = 0 : 1 : zipPlus myFibs (tail myFibs)
|
||||
result = take 15 myFibs
|
||||
")
|
||||
|
||||
(hk-test
|
||||
"fib.hs — first 15 Fibonacci numbers"
|
||||
(hk-as-list (hk-prog-val hk-fib-source "result"))
|
||||
(list 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377))
|
||||
|
||||
;; Spot-check that the user-defined zipPlus is also reachable
|
||||
(hk-test
|
||||
"fib.hs — zipPlus is a multi-clause user fn"
|
||||
(hk-as-list
|
||||
(hk-prog-val
|
||||
(str hk-fib-source "extra = zipPlus [1, 2, 3] [10, 20, 30]\n")
|
||||
"extra"))
|
||||
(list 11 22 33))
|
||||
|
||||
{:fails hk-test-fails :pass hk-test-pass :fail hk-test-fail}
|
||||
15
lib/haskell/tests/programs/fib.hs
Normal file
15
lib/haskell/tests/programs/fib.hs
Normal file
@@ -0,0 +1,15 @@
|
||||
-- fib.hs — infinite Fibonacci stream.
|
||||
--
|
||||
-- The classic two-line definition: `fibs` is a self-referential
|
||||
-- lazy list built by zipping itself with its own tail, summing the
|
||||
-- pair at each step. Without lazy `:` (cons cell with thunked head
|
||||
-- and tail) this would diverge before producing any output; with
|
||||
-- it, `take 15 fibs` evaluates exactly as much of the spine as
|
||||
-- demanded.
|
||||
|
||||
zipPlus (x:xs) (y:ys) = x + y : zipPlus xs ys
|
||||
zipPlus _ _ = []
|
||||
|
||||
myFibs = 0 : 1 : zipPlus myFibs (tail myFibs)
|
||||
|
||||
result = take 15 myFibs
|
||||
Reference in New Issue
Block a user