CSV-shaped transform: clean -> derive -> project
Each row is a Map as if parsed from a CSV header. Demonstrates a block-lambda map(...) that derives new columns, filter for valid rows, and select to project the output shape.
A Soma program from the data part of the verified corpus: 51 lines, cells CsvTransform, CsvTransformTests. It passes soma check with soma 3.2.4.
How it is built
The cell CsvTransform has no face and no memory. Handlers: raw (line 6), line_items (line 17), invoice (line 27), grand_total (line 29) and run (line 31).
The file also holds 1 test cell (CsvTransformTests) with 5 assertions, run by soma test.
The source
csv_transform.cell
// CSV-shaped transform: clean -> derive -> project. Each row is a Map as if
// parsed from a CSV header. Demonstrates a block-lambda map(...) that derives
// new columns, filter for valid rows, and select to project the output shape.
cell CsvTransform {
on raw() {
return list(
map("sku", "A1", "qty", 4, "unit_price", 25, "tax_rate", 20),
map("sku", "B2", "qty", 0, "unit_price", 99, "tax_rate", 20),
map("sku", "C3", "qty", 2, "unit_price", 50, "tax_rate", 5),
map("sku", "D4", "qty", 10, "unit_price", 3, "tax_rate", 0),
map("sku", "E5", "qty", 1, "unit_price", 200, "tax_rate", 20)
)
}
// Derive net, tax, gross per line; keep only rows that actually shipped.
on line_items() {
return raw()
|> filter_by("qty", ">", 0)
|> map(r => {
let net = r.qty * r.unit_price
let tax = floor(net * r.tax_rate / 100)
r |> with("net", net) |> with("tax", tax) |> with("gross", net + tax)
})
}
on invoice() { return line_items() |> select("sku", "qty", "net", "tax", "gross") }
on grand_total() { return line_items() |> sum_by("gross") }
on run() {
for r in invoice() { print("{r.sku} x{r.qty}: net {r.net} + tax {r.tax} = {r.gross}") }
return grand_total()
}
}
cell test CsvTransformTests {
rules {
// B2 has qty 0 -> dropped; 4 of 5 rows remain
assert len(line_items()) == 4
// A1: net 100, tax 20, gross 120
assert (line_items() |> filter_by("sku", "=", "A1"))[0].gross == 120
// C3: net 100, tax 5 (5%), gross 105
assert (line_items() |> filter_by("sku", "=", "C3"))[0].tax == 5
// D4: tax_rate 0 -> tax 0
assert (line_items() |> filter_by("sku", "=", "D4"))[0].tax == 0
// grand total: 120 + 105 + 30 + 240 = 495
assert grand_total() == 495
}
}What the toolchain says
$ soma check csv_transform.cell
✓ All checks passed.$ soma test csv_transform.cell
test CsvTransformTests ...
✓ assert len(line_items()) == 4
✓ assert (line_items() |> filter_by("sku", "=", "A1"))[0].gross == 120
✓ assert (line_items() |> filter_by("sku", "=", "C3"))[0].tax == 5
✓ assert (line_items() |> filter_by("sku", "=", "D4"))[0].tax == 0
✓ assert grand_total() == 495
5 tests: 5 passed, 0 failed$ soma verify csv_transform.cell
Verifying csv_transform.cell...
No state machine in this program: nothing to prove beyond `soma check` (invariants and lifecycles are what verify proves).
VERIFY OK (vacuous — no state machine)Builtins used
filter_by, floor, len, list, map, print, select, sum_by, with