/- Copyright (c) 2022 Mac Malone. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Mac Malone -/ namespace Lake /-- A sequence of calls donated by the key type `κ`. -/ abbrev CallStack κ := List κ /-- A `CallStack` ending in a cycle. -/ abbrev Cycle κ := CallStack κ /-- A transformer that equips a monad with a `CallStack` to detect cycles. -/ abbrev CycleT κ m := ReaderT (CallStack κ) <| ExceptT (Cycle κ) m /-- Add `key` to the monad's `CallStack` before invoking `act`. If adding `key` produces a cycle, the cyclic call stack is thrown. -/ @[inline] def guardCycle [BEq κ] [Monad m] (key : κ) (act : CycleT κ m α) : CycleT κ m α := do let parents ← read if parents.contains key then throw <| key :: (parents.partition (· != key)).1 ++ [key] else act (key :: parents)