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: NAME RUNNER-FN PATH
|
||||||
SUITES=(
|
SUITES=(
|
||||||
"basic flow-basic-tests-run! lib/flow/tests/basic.sx"
|
"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
|
TMPFILE=$(mktemp); trap "rm -f $TMPFILE" EXIT
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
{
|
{
|
||||||
"total": 18,
|
"total": 24,
|
||||||
"passed": 18,
|
"passed": 24,
|
||||||
"failed": 0,
|
"failed": 0,
|
||||||
"suites": {
|
"suites": {
|
||||||
"basic": { "passed": 18, "total": 18 }
|
"basic": { "passed": 18, "total": 18 },
|
||||||
|
"control": { "passed": 6, "total": 6 }
|
||||||
},
|
},
|
||||||
"phases": {
|
"phases": {
|
||||||
"phase1": "in-progress"
|
"phase1": "done",
|
||||||
|
"phase2": "in-progress"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# flow-on-sx Scoreboard
|
# 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`
|
`bash lib/flow/conformance.sh`
|
||||||
|
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
| Suite | Passing | Covers |
|
| Suite | Passing | Covers |
|
||||||
|-------|--------:|--------|
|
|-------|--------:|--------|
|
||||||
| basic | 18 | Phase 1: single nodes, linear sequence, data-flow threading, defflow, parallel fan/join, nested composition, publish-shaped flow |
|
| 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
|
## Architecture
|
||||||
|
|
||||||
@@ -34,8 +35,7 @@ capture the flow continuation directly.
|
|||||||
|
|
||||||
## Phases
|
## Phases
|
||||||
|
|
||||||
- [~] Phase 1 — Declarative DAG + sequential execution (combinators + 18 tests done;
|
- [x] Phase 1 — Declarative DAG + sequential execution (combinators + 18 tests, `flow/start`)
|
||||||
`flow/start` done)
|
- [~] Phase 2 — Control flow + error handling (`branch` done)
|
||||||
- [ ] Phase 2 — Control flow + error handling
|
|
||||||
- [ ] Phase 3 — Suspend / resume (the showcase)
|
- [ ] Phase 3 — Suspend / resume (the showcase)
|
||||||
- [ ] Phase 4 — Distributed nodes via fed-sx
|
- [ ] Phase 4 — Distributed nodes via fed-sx
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
;; Scheme interpreter so that Phase 3's `suspend` (call/cc) can capture the
|
;; Scheme interpreter so that Phase 3's `suspend` (call/cc) can capture the
|
||||||
;; flow continuation directly.
|
;; 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-node f) — wrap a 1-arg procedure as a node (identity)
|
||||||
;; (flow-id input) — pass the upstream value through unchanged
|
;; (flow-id input) — pass the upstream value through unchanged
|
||||||
;; (flow-const v) — node that ignores input and yields v
|
;; (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
|
;; (parallel n ...) — fan input to every child, join results into a list
|
||||||
;; (SEQUENTIAL evaluation; true concurrency is Phase 3)
|
;; (SEQUENTIAL evaluation; true concurrency is Phase 3)
|
||||||
;; (defflow name body)— bind a named flow
|
;; (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
|
(define
|
||||||
flow-combinators-src
|
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-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
|
(define
|
||||||
flow-load-combinators!
|
flow-load-combinators!
|
||||||
(fn
|
(fn
|
||||||
(env)
|
(env)
|
||||||
(begin
|
(begin
|
||||||
(scheme-eval-program (scheme-parse-all flow-combinators-src) env)
|
(scheme-eval-program (scheme-parse-all flow-combinators-src) env)
|
||||||
|
(scheme-eval-program (scheme-parse-all flow-control-src) env)
|
||||||
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)
|
## 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
|
## Ground rules
|
||||||
|
|
||||||
@@ -75,7 +75,8 @@ lib/flow/spec.sx lib/flow/runtime.sx lib/flow/store.sx
|
|||||||
|
|
||||||
## Phase 2 — Control flow + error handling
|
## 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
|
- [ ] `retry n [backoff]` — re-runs node up to n times on exception
|
||||||
- [ ] `timeout ms` — bounds node execution
|
- [ ] `timeout ms` — bounds node execution
|
||||||
- [ ] `try-catch` — exception handler with reified error
|
- [ ] `try-catch` — exception handler with reified error
|
||||||
|
|||||||
Reference in New Issue
Block a user