lean4-htt/src/Init/Control/Except.lean
2021-02-20 17:01:27 -08:00

162 lines
6 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
Copyright (c) 2017 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Jared Roesch, Sebastian Ullrich
The Except monad transformer.
-/
prelude
import Init.Control.Basic
import Init.Control.Id
import Init.Coe
namespace Except
variable {ε : Type u}
@[inline] protected def pure (a : α) : Except ε α :=
Except.ok a
@[inline] protected def map (f : α → β) : Except ε α → Except ε β
| Except.error err => Except.error err
| Except.ok v => Except.ok <| f v
@[simp] theorem map_id : Except.map (ε := ε) (α := α) (β := α) id = id := by
apply funext
intro e
simp [Except.map]; cases e <;> rfl
@[inline] protected def mapError (f : ε → ε') : Except ε α → Except ε' α
| Except.error err => Except.error <| f err
| Except.ok v => Except.ok v
@[inline] protected def bind (ma : Except ε α) (f : α → Except ε β) : Except ε β :=
match ma with
| Except.error err => Except.error err
| Except.ok v => f v
@[inline] protected def toBool : Except ε α → Bool
| Except.ok _ => true
| Except.error _ => false
@[inline] protected def toOption : Except ε α → Option α
| Except.ok a => some a
| Except.error _ => none
@[inline] protected def tryCatch (ma : Except ε α) (handle : ε → Except ε α) : Except ε α :=
match ma with
| Except.ok a => Except.ok a
| Except.error e => handle e
instance : Monad (Except ε) where
pure := Except.pure
bind := Except.bind
map := Except.map
end Except
def ExceptT (ε : Type u) (m : Type u → Type v) (α : Type u) : Type v :=
m (Except ε α)
@[inline] def ExceptT.mk {ε : Type u} {m : Type u → Type v} {α : Type u} (x : m (Except ε α)) : ExceptT ε m α := x
@[inline] def ExceptT.run {ε : Type u} {m : Type u → Type v} {α : Type u} (x : ExceptT ε m α) : m (Except ε α) := x
namespace ExceptT
variable {ε : Type u} {m : Type u → Type v} [Monad m]
@[inline] protected def pure {α : Type u} (a : α) : ExceptT ε m α :=
ExceptT.mk <| pure (Except.ok a)
@[inline] protected def bindCont {α β : Type u} (f : α → ExceptT ε m β) : Except ε α → m (Except ε β)
| Except.ok a => f a
| Except.error e => pure (Except.error e)
@[inline] protected def bind {α β : Type u} (ma : ExceptT ε m α) (f : α → ExceptT ε m β) : ExceptT ε m β :=
ExceptT.mk <| ma >>= ExceptT.bindCont f
@[inline] protected def map {α β : Type u} (f : α → β) (x : ExceptT ε m α) : ExceptT ε m β :=
ExceptT.mk <| x >>= fun a => match a with
| (Except.ok a) => pure <| Except.ok (f a)
| (Except.error e) => pure <| Except.error e
@[inline] protected def lift {α : Type u} (t : m α) : ExceptT ε m α :=
ExceptT.mk <| Except.ok <$> t
instance : MonadLift (Except ε) (ExceptT ε m) := ⟨fun e => ExceptT.mk <| pure e⟩
instance : MonadLift m (ExceptT ε m) := ⟨ExceptT.lift⟩
@[inline] protected def tryCatch {α : Type u} (ma : ExceptT ε m α) (handle : ε → ExceptT ε m α) : ExceptT ε m α :=
ExceptT.mk <| ma >>= fun res => match res with
| Except.ok a => pure (Except.ok a)
| Except.error e => (handle e)
instance : MonadFunctor m (ExceptT ε m) := ⟨fun f x => f x⟩
instance : Monad (ExceptT ε m) where
pure := ExceptT.pure
bind := ExceptT.bind
map := ExceptT.map
@[inline] protected def adapt {ε' α : Type u} (f : ε → ε') : ExceptT ε m α → ExceptT ε' m α := fun x =>
ExceptT.mk <| Except.mapError f <$> x
end ExceptT
instance (m : Type u → Type v) (ε₁ : Type u) (ε₂ : Type u) [Monad m] [MonadExceptOf ε₁ m] : MonadExceptOf ε₁ (ExceptT ε₂ m) where
throw e := ExceptT.mk <| throwThe ε₁ e
tryCatch x handle := ExceptT.mk <| tryCatchThe ε₁ x handle
instance (m : Type u → Type v) (ε : Type u) [Monad m] : MonadExceptOf ε (ExceptT ε m) where
throw e := ExceptT.mk <| pure (Except.error e)
tryCatch := ExceptT.tryCatch
instance [Monad m] [Inhabited ε] : Inhabited (ExceptT ε m α) where
default := throw arbitrary
instance (ε) : MonadExceptOf ε (Except ε) where
throw := Except.error
tryCatch := Except.tryCatch
namespace MonadExcept
variable {ε : Type u} {m : Type v → Type w}
/-- Alternative orelse operator that allows to select which exception should be used.
The default is to use the first exception since the standard `orelse` uses the second. -/
@[inline] def orelse' [MonadExcept ε m] {α : Type v} (t₁ t₂ : m α) (useFirstEx := true) : m α :=
tryCatch t₁ fun e₁ => tryCatch t₂ fun e₂ => throw (if useFirstEx then e₁ else e₂)
end MonadExcept
@[inline] def observing {ε α : Type u} {m : Type u → Type v} [Monad m] [MonadExcept ε m] (x : m α) : m (Except ε α) :=
tryCatch (do let a ← x; pure (Except.ok a)) (fun ex => pure (Except.error ex))
instance (ε : Type u) (m : Type u → Type v) [Monad m] : MonadControl m (ExceptT ε m) where
stM := Except ε
liftWith f := liftM <| f fun x => x.run
restoreM x := x
class MonadFinally (m : Type u → Type v) where
tryFinally' {α β} : m α → (Option α → m β) → m (α × β)
export MonadFinally (tryFinally')
/-- Execute `x` and then execute `finalizer` even if `x` threw an exception -/
@[inline] def tryFinally {m : Type u → Type v} {α β : Type u} [MonadFinally m] [Functor m] (x : m α) (finalizer : m β) : m α :=
let y := tryFinally' x (fun _ => finalizer)
(·.1) <$> y
instance Id.finally : MonadFinally Id where
tryFinally' := fun x h =>
let a := x
let b := h (some x)
pure (a, b)
instance ExceptT.finally {m : Type u → Type v} {ε : Type u} [MonadFinally m] [Monad m] : MonadFinally (ExceptT ε m) where
tryFinally' := fun x h => ExceptT.mk do
let r ← tryFinally' x fun e? => match e? with
| some (Except.ok a) => h (some a)
| _ => h none
match r with
| (Except.ok a, Except.ok b) => pure (Except.ok (a, b))
| (_, Except.error e) => pure (Except.error e) -- second error has precedence
| (Except.error e, _) => pure (Except.error e)