import system.io def lifted_test : reader_t ℕ (state_t ℕ io) unit := do 0 ← read, -- unlifted 1 ← get, -- transparently lifted through reader_t put 2, 2 ← get, modify (+1), 3 ← get, put 4 <|> put 5, 4 ← get, -- left branch wins modify (+1) >> monad_fail.fail "" <|> modify (+2), 6 ← get, -- an outer state_t makes the state backtrack pure () #eval (lifted_test.run 0).run 1 def infer_test {m n} [monad_state_lift ℕ m n] [monad m] [monad n] : n ℕ := do n ← get, -- can infer σ through class inference pure n.succ def zoom_test : reader_t ℕ (state_t (ℕ × ℕ) io) unit := do -- zoom in on second elem zoom (λ p, (prod.snd p, prod.fst p)) -- note: type of `p` is not known yet (λ m n, (n, m)) -- note: inner monad type must be known -- note: the reader_t layer is not discarded (read >>= put : reader_t ℕ (state_t ℕ io) punit), (1, 0) ← get, -- you can also (mis?)use zoom to zoom out to a larger state 3 ← zoom (λ p, ((p, 3), p)) (λ q _, q.1) ((do q ← get, pure q.2) : reader_t ℕ (state_t ((ℕ × ℕ) × ℕ) io) ℕ), pure () #eval (zoom_test.run 0).run (1, 2) def bistate_test : state_t ℕ (state_t bool io) unit := do 0 ← get, -- outer state_t wins -- manual tt ← monad_lift (get : state_t bool io bool), -- needs to mention inner monad tt ← get_type io bool, pure () #eval (bistate_test.run 0).run tt