; A traffic light at a crossing, driven by a clock and a pedestrian button. ; Each state carries how long it has left; a fault drops the light to ; flashing, and a supervisor decides whether to reset it. data Light Green(left: i32) Yellow(left: i32, walk: bool) Red(left: i32, walk: bool) Flashing() struct Fault tick: i32 const green-time = 4 const yellow-time = 1 const red-time = 3 fn next(l: Light, pressed: bool) -> Light match l Green(left) -> if left > 1 and not pressed then Light.Green{.left left - 1} else Light.Yellow{.left yellow-time, .walk pressed} Yellow(left, walk) -> if left > 1 Light.Yellow{.left left - 1, .walk walk} else Light.Red{.left red-time, .walk walk} Red(left, walk) -> if left > 1 then Light.Red{.left left - 1, .walk walk} else Light.Green{.left green-time} Flashing -> Light.Flashing{} fn show(l: Light) -> str match l Green(_) -> "G" Yellow(_, _) -> "Y" Red(_, walk) -> if walk then "W" else "R" Flashing -> "*" ; Runs the light for ticks steps; a fault at fault-at is signalled, and ; whoever handles it may reset the light to red. fn run(ticks: i32, presses: [const i32], fault-at: i32) -> () let l = Light.Red{.left 1, .walk false} let p = 0 let t = 0 until :clock t >= ticks let pressed = p < length(presses) and presses[p] == t if pressed ++(p) if t == fault-at l = restart-case error(Fault{.tick t}) l restart reset() "Put the light back to red and carry on" Light.Red{.left red-time, .walk false} restart flash() Light.Flashing{} match l Flashing -> print(show(l)) break :clock _ -> print(show(l)) l = next(l, pressed) t += 1 println("") fn main() -> i32 let none = [-1] let two = [1 9] run(12, slice(none), -1) run(12, slice(two), -1) handler-bind run(12, slice(none), 5) on Fault(f) invoke-restart('reset) handler-bind run(12, slice(none), 5) on Fault(f) invoke-restart('flash) println: handler-case run(12, slice(none), 2) "no fault" on Fault(f) println("") "fault at tick" 0