flow: branch combinator (conditional) + 6 tests
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 50s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 50s
Phase 2 control flow. (branch pred then else) selects then/else node by running pred on the threaded input; named 'branch' since 'cond' is a Scheme special form. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -22,6 +22,7 @@ VERBOSE="${1:-}"
|
||||
# Suites: NAME RUNNER-FN PATH
|
||||
SUITES=(
|
||||
"basic flow-basic-tests-run! lib/flow/tests/basic.sx"
|
||||
"control flow-ctl-tests-run! lib/flow/tests/control.sx"
|
||||
)
|
||||
|
||||
TMPFILE=$(mktemp); trap "rm -f $TMPFILE" EXIT
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
{
|
||||
"total": 18,
|
||||
"passed": 18,
|
||||
"total": 24,
|
||||
"passed": 24,
|
||||
"failed": 0,
|
||||
"suites": {
|
||||
"basic": { "passed": 18, "total": 18 }
|
||||
"basic": { "passed": 18, "total": 18 },
|
||||
"control": { "passed": 6, "total": 6 }
|
||||
},
|
||||
"phases": {
|
||||
"phase1": "in-progress"
|
||||
"phase1": "done",
|
||||
"phase2": "in-progress"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# flow-on-sx Scoreboard
|
||||
|
||||
**All tests pass: 18 / 18 across 1 suite.**
|
||||
**All tests pass: 24 / 24 across 2 suites.**
|
||||
|
||||
`bash lib/flow/conformance.sh`
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
| Suite | Passing | Covers |
|
||||
|-------|--------:|--------|
|
||||
| basic | 18 | Phase 1: single nodes, linear sequence, data-flow threading, defflow, parallel fan/join, nested composition, publish-shaped flow |
|
||||
| control | 6 | Phase 2: `branch` conditional — true/false select, threaded predicate, full-node branches, nested 3-way, approval gate |
|
||||
|
||||
## Architecture
|
||||
|
||||
@@ -34,8 +35,7 @@ capture the flow continuation directly.
|
||||
|
||||
## Phases
|
||||
|
||||
- [~] Phase 1 — Declarative DAG + sequential execution (combinators + 18 tests done;
|
||||
`flow/start` done)
|
||||
- [ ] Phase 2 — Control flow + error handling
|
||||
- [x] Phase 1 — Declarative DAG + sequential execution (combinators + 18 tests, `flow/start`)
|
||||
- [~] Phase 2 — Control flow + error handling (`branch` done)
|
||||
- [ ] Phase 3 — Suspend / resume (the showcase)
|
||||
- [ ] Phase 4 — Distributed nodes via fed-sx
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
;; Scheme interpreter so that Phase 3's `suspend` (call/cc) can capture the
|
||||
;; flow continuation directly.
|
||||
;;
|
||||
;; Phase 1 combinators:
|
||||
;; Phase 1 combinators (flow-combinators-src):
|
||||
;; (flow-node f) — wrap a 1-arg procedure as a node (identity)
|
||||
;; (flow-id input) — pass the upstream value through unchanged
|
||||
;; (flow-const v) — node that ignores input and yields v
|
||||
@@ -15,15 +15,24 @@
|
||||
;; (parallel n ...) — fan input to every child, join results into a list
|
||||
;; (SEQUENTIAL evaluation; true concurrency is Phase 3)
|
||||
;; (defflow name body)— bind a named flow
|
||||
;;
|
||||
;; Phase 2 combinators (flow-control-src):
|
||||
;; (branch pred then else) — pred on input selects then/else node
|
||||
;; (`cond` is a Scheme special form, so the combinator is named `branch`)
|
||||
|
||||
(define
|
||||
flow-combinators-src
|
||||
"(define (flow-node f) f)\n (define (flow-id input) input)\n (define (flow-const v) (lambda (input) v))\n (define (flow-seq-step ns v)\n (if (null? ns) v (flow-seq-step (cdr ns) ((car ns) v))))\n (define sequence (lambda ns (lambda (input) (flow-seq-step ns input))))\n (define parallel (lambda ns (lambda (input) (map (lambda (n) (n input)) ns))))\n (define-syntax defflow\n (syntax-rules ()\n ((defflow nm body) (define nm body))))")
|
||||
|
||||
(define
|
||||
flow-control-src
|
||||
"(define (branch pred then else)\n (lambda (input) (if (pred input) (then input) (else input))))")
|
||||
|
||||
(define
|
||||
flow-load-combinators!
|
||||
(fn
|
||||
(env)
|
||||
(begin
|
||||
(scheme-eval-program (scheme-parse-all flow-combinators-src) env)
|
||||
(scheme-eval-program (scheme-parse-all flow-control-src) env)
|
||||
env)))
|
||||
|
||||
53
lib/flow/tests/control.sx
Normal file
53
lib/flow/tests/control.sx
Normal file
@@ -0,0 +1,53 @@
|
||||
;; lib/flow/tests/control.sx — Phase 2: control flow + error handling.
|
||||
|
||||
(define flow-ctl-pass 0)
|
||||
(define flow-ctl-fail 0)
|
||||
(define flow-ctl-fails (list))
|
||||
|
||||
(define
|
||||
flow-ctl-test
|
||||
(fn
|
||||
(name actual expected)
|
||||
(if
|
||||
(= actual expected)
|
||||
(set! flow-ctl-pass (+ flow-ctl-pass 1))
|
||||
(begin
|
||||
(set! flow-ctl-fail (+ flow-ctl-fail 1))
|
||||
(append! flow-ctl-fails {:name name :expected expected :actual actual})))))
|
||||
|
||||
(define flow-c (fn (src) (flow-run src)))
|
||||
(define flow-cs (fn (src) (get (flow-run src) :scm-string)))
|
||||
|
||||
;; ── branch ──────────────────────────────────────────────────────
|
||||
(flow-ctl-test
|
||||
"branch: true selects then"
|
||||
(flow-c
|
||||
"(flow/start (branch (lambda (x) (> x 0)) (lambda (x) (* x 100)) (lambda (x) (- 0 x))) 5)")
|
||||
500)
|
||||
(flow-ctl-test
|
||||
"branch: false selects else"
|
||||
(flow-c
|
||||
"(flow/start (branch (lambda (x) (> x 0)) (lambda (x) (* x 100)) (lambda (x) (- 0 x))) -3)")
|
||||
3)
|
||||
(flow-ctl-test
|
||||
"branch: predicate sees the threaded input"
|
||||
(flow-c
|
||||
"(flow/start (sequence (lambda (x) (+ x 1)) (branch (lambda (x) (> x 3)) (flow-const 100) (flow-const 0))) 3)")
|
||||
100)
|
||||
(flow-ctl-test
|
||||
"branch: branches are full nodes (sequence inside)"
|
||||
(flow-c
|
||||
"(flow/start (branch (lambda (x) (< x 10)) (sequence (lambda (x) (+ x 1)) (lambda (x) (* x 2))) (flow-const 0)) 4)")
|
||||
10)
|
||||
(flow-ctl-test
|
||||
"branch: nested branch (3-way sign)"
|
||||
(flow-c
|
||||
"(defflow sign (branch (lambda (x) (> x 0)) (flow-const 1) (branch (lambda (x) (< x 0)) (flow-const -1) (flow-const 0)))) (list (flow/start sign 7) (flow/start sign -7) (flow/start sign 0))")
|
||||
(list 1 -1 0))
|
||||
(flow-ctl-test
|
||||
"branch: publish-shaped approval gate"
|
||||
(flow-cs
|
||||
"(defflow publish (branch (lambda (post) (>= (string-length post) 3)) (lambda (post) (string-append post \" [published]\")) (lambda (post) (string-append post \" [rejected]\")))) (flow/start publish \"ok\")")
|
||||
"ok [rejected]")
|
||||
|
||||
(define flow-ctl-tests-run! (fn () {:total (+ flow-ctl-pass flow-ctl-fail) :passed flow-ctl-pass :failed flow-ctl-fail :fails flow-ctl-fails}))
|
||||
@@ -16,7 +16,7 @@ federation extension via fed-sx for remote-node execution.
|
||||
|
||||
## Status (rolling)
|
||||
|
||||
`bash lib/flow/conformance.sh` → **18/18** (Phase 1 in progress)
|
||||
`bash lib/flow/conformance.sh` → **24/24** (Phase 1 done; Phase 2 in progress)
|
||||
|
||||
## Ground rules
|
||||
|
||||
@@ -75,7 +75,8 @@ lib/flow/spec.sx lib/flow/runtime.sx lib/flow/store.sx
|
||||
|
||||
## Phase 2 — Control flow + error handling
|
||||
|
||||
- [ ] `cond` combinator — predicate selects branch
|
||||
- [x] `cond` combinator — predicate selects branch (named `branch`; `cond` is a
|
||||
Scheme special form). `(branch pred then else)` — 6 tests.
|
||||
- [ ] `retry n [backoff]` — re-runs node up to n times on exception
|
||||
- [ ] `timeout ms` — bounds node execution
|
||||
- [ ] `try-catch` — exception handler with reified error
|
||||
|
||||
Reference in New Issue
Block a user