25 tests pass on OCaml (4357 total) and JS. Promise represented as
mutable dict {:_promise true :forced :thunk :value}; delay-force
adds :_iterative for chain-following semantics.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
150 lines
3.7 KiB
Plaintext
150 lines
3.7 KiB
Plaintext
(defsuite
|
|
"promises"
|
|
(deftest
|
|
"delay creates a promise"
|
|
(do (assert (promise? (delay 42)))))
|
|
(deftest
|
|
"delay does not evaluate immediately"
|
|
(do
|
|
(let
|
|
((count 0))
|
|
(let
|
|
((p (delay (do (set! count (+ count 1)) count))))
|
|
(assert= 0 count)))))
|
|
(deftest
|
|
"force evaluates the expression"
|
|
(do (assert= 42 (force (delay 42)))))
|
|
(deftest
|
|
"force with arithmetic"
|
|
(do (assert= 10 (force (delay (+ 3 7))))))
|
|
(deftest
|
|
"force memoises result"
|
|
(do
|
|
(let
|
|
((count 0))
|
|
(let
|
|
((p (delay (do (set! count (+ count 1)) count))))
|
|
(force p)
|
|
(force p)
|
|
(assert= 1 count)))))
|
|
(deftest
|
|
"force returns same value on repeated calls"
|
|
(do
|
|
(let
|
|
((p (delay (+ 1 2))))
|
|
(assert= 3 (force p))
|
|
(assert= 3 (force p)))))
|
|
(deftest
|
|
"make-promise creates an already-forced promise"
|
|
(do
|
|
(let
|
|
((p (make-promise 99)))
|
|
(assert (promise? p))
|
|
(assert= 99 (force p)))))
|
|
(deftest
|
|
"make-promise memoises without evaluating"
|
|
(do
|
|
(let
|
|
((count 0))
|
|
(let
|
|
((p (make-promise 42)))
|
|
(force p)
|
|
(force p)
|
|
(assert= 0 count)))))
|
|
(deftest
|
|
"promise? returns true for delay"
|
|
(do (assert (promise? (delay 1)))))
|
|
(deftest
|
|
"promise? returns true for make-promise"
|
|
(do (assert (promise? (make-promise 1)))))
|
|
(deftest
|
|
"promise? returns false for non-promise"
|
|
(do
|
|
(assert= false (promise? 42))
|
|
(assert= false (promise? "hello"))
|
|
(assert= false (promise? nil))
|
|
(assert= false (promise? (list 1 2)))))
|
|
(deftest
|
|
"force non-promise returns value unchanged"
|
|
(do
|
|
(assert= 42 (force 42))
|
|
(assert= "hi" (force "hi"))
|
|
(assert= nil (force nil))))
|
|
(deftest
|
|
"delay captures environment"
|
|
(do
|
|
(let
|
|
((x 10))
|
|
(let
|
|
((p (delay (+ x 5))))
|
|
(assert= 15 (force p))))))
|
|
(deftest
|
|
"delay-force basic"
|
|
(do (assert= 42 (force (delay-force (delay 42))))))
|
|
(deftest
|
|
"delay-force chains"
|
|
(do
|
|
(assert=
|
|
5
|
|
(force (delay-force (delay-force (delay 5)))))))
|
|
(deftest
|
|
"delay with string"
|
|
(do (assert= "hello" (force (delay "hello")))))
|
|
(deftest
|
|
"delay with list"
|
|
(do
|
|
(assert-equal
|
|
(list 1 2 3)
|
|
(force (delay (list 1 2 3))))))
|
|
(deftest
|
|
"delay with function call"
|
|
(do (assert= 6 (force (delay (* 2 3))))))
|
|
(deftest
|
|
"nested delay"
|
|
(do
|
|
(let
|
|
((p (delay (delay 99))))
|
|
(assert (promise? (force p))))))
|
|
(deftest
|
|
"force already forced promise"
|
|
(do
|
|
(let
|
|
((p (make-promise 7)))
|
|
(assert= 7 (force p))
|
|
(assert= 7 (force p)))))
|
|
(deftest
|
|
"lazy stream first element"
|
|
(do
|
|
(define (stream-cons x s) (delay (list x s)))
|
|
(define (stream-car s) (first (force s)))
|
|
(define (stream-cdr s) (nth (force s) 1))
|
|
(let
|
|
((s (stream-cons 1 (stream-cons 2 (stream-cons 3 nil)))))
|
|
(assert= 1 (stream-car s))
|
|
(assert= 2 (stream-car (stream-cdr s))))))
|
|
(deftest
|
|
"delay-force is a promise"
|
|
(do (assert (promise? (delay-force (delay 1))))))
|
|
(deftest
|
|
"force with side effects runs once"
|
|
(do
|
|
(let
|
|
((log (list)))
|
|
(let
|
|
((p (delay (do (set! log (cons 42 log)) 42))))
|
|
(force p)
|
|
(force p)
|
|
(assert= 1 (len log))))))
|
|
(deftest
|
|
"make-promise with nil"
|
|
(do
|
|
(let
|
|
((p (make-promise nil)))
|
|
(assert (promise? p))
|
|
(assert= nil (force p)))))
|
|
(deftest
|
|
"delay in let binding"
|
|
(do
|
|
(let
|
|
((p (delay (+ 10 20))))
|
|
(assert= 30 (force p)))))) |