import Base
# A reusable tree of rows. Internal nodes expose independent work to Bend.
type Batch<-A: Data> is Data:
Empty{}
Item{value: A}
Fork{left: Batch, right: Batch}
def count(-A: Data, rows: Batch) -> Nat:
match rows:
case Empty{}:
0n
case Item{value}:
1n
case Fork{left, right}:
a b = count(A, left) count(A, right)
Nat.add(a, b)
# Split list ranges into a balanced tree; construction takes O(n log n).
# fuel bounds recursion; from_list supplies a sufficient bound (list length).
def build(-A: Data, +fuel: Nat, n: Nat, +xs: List<&2, A>) -> Batch:
match fuel n:
case 0n n:
Empty{}
case 1n+p 0n:
Empty{}
case 1n+p 1n+0n:
match xs:
case Nil{}:
Empty{}
case h <> t:
Item{h}
case 1n+p 1n+1n+k:
+size = Nat.add(2n, k)
+half = Nat.div(size, 2n)
left = build(A, p, half, List.take(&2, A, xs, half))
right = build(A, p, Nat.sub(size, half), List.drop(&2, A, xs, half))
Fork{left, right}
def from_list(-A: Data, +xs: List<&2, A>) -> Batch:
+n = List.length(&2, A, xs)
build(A, n, n, xs)
def to_list(-A: Data, rows: Batch) -> List<&2, A>:
match rows:
case Empty{}:
Nil{}
case Item{value}:
[value]
case Fork{left, right}:
List.append(&2, A, to_list(A, left), to_list(A, right))
# Template callbacks are reusable and specialized at compile time.
def map(~A: Data, ~B: Data, ~f: A -> B, rows: Batch) -> Batch:
match rows:
case Empty{}:
Empty{}
case Item{value}:
Item{f(value)}
case Fork{left, right}:
a b = map(~A, ~B, ~f, left) map(~A, ~B, ~f, right)
Fork{a, b}
# The join operation should have an identity zero and be associative in the
# intended arithmetic. F32 results can vary with grouping because of rounding.
def fold(~A: Data, ~B: Data, ~leaf: A -> B, ~join: B -> B -> B, +zero: B, rows: Batch) -> B:
match rows:
case Empty{}:
zero
case Item{value}:
leaf(value)
case Fork{left, right}:
a b = fold(~A, ~B, ~leaf, ~join, zero, left) fold(~A, ~B, ~leaf, ~join, zero, right)
join(a, b)