; A ledger that applies transfers between accounts. A transfer that would ; overdraw signals, and the caller picks a restart: skip it, cap it at what ; the account holds, or allow an overdraft up to a limit it supplies. defstruct(Overdraft, :parent, Error, [account i32 short i64]) struct Audit account: i32 amount: i64 once balances: [4 i64] once audits: i32 once log: i64 ; Every transfer leaves a digit in the log when it is done with, however it ; ended: 1 applied, 2 left through a restart. fn note(d: i64) -> () log = log * 10 + d fn withdraw(account: i32, amount: i64) -> i64 let have = balances[account] if amount > have let short = amount - have restart-case error(Overdraft{.account account, .short short}) restart skip() return 0 restart cap() return withdraw(account, have) restart allow(limit: i64) if short > limit return 0 if amount >= 100 signal(Audit{.account account, .amount amount}) balances[account] -= amount amount fn transfer(from: i32, to: i32, amount: i64) -> i64 let applied: i64 = 0 defer note(if applied == amount then 1 else 2) applied = withdraw(from, amount) balances[to] += applied applied fn run(policy) -> () balances = [100 50 0 10] log = 0 handler-bind transfer(0, 2, 30) transfer(1, 2, 80) transfer(3, 0, 25) transfer(0, 1, 100) on Overdraft(o) match policy :skip -> invoke-restart('skip) :cap -> invoke-restart('cap) _ -> invoke-restart('allow, i64(20)) on Audit(a) audits += 1 println(policy, slice(balances), "log", log) fn main() -> i32 run(:skip) run(:cap) run(:allow) println("audited", audits) let caught = handler-case balances = [0 0 0 0] withdraw(2, 5) on Overdraft(o) println("unhandled overdraft on", o.account, "short by", o.short) -1 println("caught", caught) 0