Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gen/apply.lean
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import init.lean.config system.io
import init.lean.config init.io
open io

@[reducible] def m := reader_t handle io
Expand Down
4 changes: 2 additions & 2 deletions library/init/coe.lean
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ universes u₁ u₂ u₃
instance lift_trans {a : Sort u₁} {b : Sort u₂} {c : Sort u₃} [has_lift a b] [has_lift_t b c] : has_lift_t a c :=
⟨λ x, lift_t (lift x : b)⟩

instance lift_base {a : Sort u} {b : Sort v} [has_lift a b] : has_lift_t a b :=
lift
instance lift_refl {a : Sort u} : has_lift_t a a :=
id

instance coe_trans {a : Sort u₁} {b : Sort u₂} {c : Sort u₃} [has_coe a b] [has_coe_t b c] : has_coe_t a c :=
⟨λ x, coe_t (coe_b x : b)⟩
Expand Down
113 changes: 113 additions & 0 deletions library/init/control/coroutine_io.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/-
Copyright (c) 2018 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura, Sebastian Ullrich
-/
prelude
import init.io init.control.coroutine

/-! A variant of `coroutine` on top of `io`. Implementation. -/

universes u v w r s

namespace coroutine_io
variables {α δ β γ : Type}

export coroutine_result_io (done yielded)

/-- `resume c a` resumes/invokes the coroutine_io `c` with input `a`. -/
@[inline] def resume : coroutine_io α δ β → α → io (coroutine_result_io α δ β)
| (mk k) a := k a

@[inline] protected def pure (b : β) : coroutine_io α δ β :=
mk $ λ _, pure (done b)

/-- Read the input argument passed to the coroutine.
Remark: should we use a different name? I added an instance [monad_reader] later. -/
@[inline] protected def read : coroutine_io α δ α :=
mk $ λ a, pure (done a)

/-- Return the control to the invoker with result `d` -/
@[inline] protected def yield (d : δ) : coroutine_io α δ punit :=
mk $ λ a : α, pure $ yielded d (coroutine_io.pure ⟨⟩)

/-
TODO(Leo): following relations have been commented because Lean4 is currently
accepting non-terminating programs.

/-- Auxiliary relation for showing that bind/pipe terminate -/
inductive direct_subcoroutine_io : coroutine_io α δ β → coroutine_io α δ β → Prop
| mk : ∀ (k : α → coroutine_result α δ β) (a : α) (d : δ) (c : coroutine_io α δ β), k a = yielded d c → direct_subcoroutine_io c (mk k)

theorem direct_subcoroutine_wf : well_founded (@direct_subcoroutine_io α δ β) :=
begin
constructor, intro c,
apply @coroutine.ind _ _ _
(λ c, acc direct_subcoroutine_io c)
(λ r, ∀ (d : δ) (c : coroutine_io α δ β), r = yielded d c → acc direct_subcoroutine_io c),
{ intros k ih, dsimp at ih, constructor, intros c' h, cases h, apply ih h_a h_d, assumption },
{ intros, contradiction },
{ intros d c ih d₁ c₁ heq, injection heq, subst c, assumption }
end

/-- Transitive closure of direct_subcoroutine. It is not used here, but may be useful when defining
more complex procedures. -/
def subcoroutine_io : coroutine_io α δ β → coroutine_io α δ β → Prop :=
tc direct_subcoroutine_io

theorem subcoroutine_wf : well_founded (@subcoroutine_io α δ β) :=
tc.wf direct_subcoroutine_wf

-- Local instances for proving termination by well founded relation

def bind_wf_inst : has_well_founded (Σ' a : coroutine_io α δ β, (β → coroutine_io α δ γ)) :=
{ r := psigma.lex direct_subcoroutine_io (λ _, empty_relation),
wf := psigma.lex_wf direct_subcoroutine_wf (λ _, empty_wf) }

def pipe_wf_inst : has_well_founded (Σ' a : coroutine_io α δ β, coroutine_io δ γ β) :=
{ r := psigma.lex direct_subcoroutine_io (λ _, empty_relation),
wf := psigma.lex_wf direct_subcoroutine_wf (λ _, empty_wf) }

local attribute [instance] wf_inst₁ wf_inst₂

open well_founded_tactics

-/

protected def bind : coroutine_io α δ β → (β → coroutine_io α δ γ) → coroutine_io α δ γ
| (mk k) f := mk $ λ a, k a >>= λ r,
match r, rfl : ∀ (n : _), n = r → _ with
| done b, _ := coroutine_io.resume (f b) a
| yielded d c, h :=
-- have direct_subcoroutine_io c (mk k), { apply direct_subcoroutine.mk k a d, rw h },
pure $ yielded d (bind c f)
-- using_well_founded { dec_tac := unfold_wf_rel >> process_lex (tactic.assumption) }

def pipe : coroutine_io α δ β → coroutine_io δ γ β → coroutine_io α γ β
| (mk k₁) (mk k₂) := mk $ λ a, do
r ← k₁ a,
match r, rfl : ∀ (n : _), n = r → _ with
| done b, h := pure (done b)
| yielded d k₁', h := do
r ← k₂ d,
pure $ match r with
| done b := done b
| yielded r k₂' :=
-- have direct_subcoroutine_io k₁' (mk k₁), { apply direct_subcoroutine.mk k₁ a d, rw h },
yielded r (pipe k₁' k₂')
-- using_well_founded { dec_tac := unfold_wf_rel >> process_lex (tactic.assumption) }

instance : monad (coroutine_io α δ) :=
{ pure := @coroutine_io.pure _ _,
bind := @coroutine_io.bind _ _ }

instance : monad_reader α (coroutine_io α δ) :=
{ read := @coroutine_io.read _ _ }

instance (α δ : Type) : coroutine.monad_coroutine α δ (coroutine_io α δ) :=
{ yield := coroutine_io.yield }

instance : monad_io (coroutine_io α δ) :=
{ monad_lift := λ _ x, mk (λ _, done <$> x) }

end coroutine_io
11 changes: 10 additions & 1 deletion library/init/control/except.lean
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ The except monad transformer.
-/
prelude
import init.control.alternative init.control.lift init.data.to_string
import init.control.monad_fail
universes u v w

inductive except (ε : Type u) (α : Type v)
Expand Down Expand Up @@ -131,8 +132,12 @@ catch t₁ $ λ _, t₂

/-- 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. -/
meta def orelse' [monad_except ε m] {α : Type v} (t₁ t₂ : m α) (use_first_ex := tt) : m α :=
def orelse' [monad_except ε m] {α : Type v} (t₁ t₂ : m α) (use_first_ex := tt) : m α :=
catch t₁ $ λ e₁, catch t₂ $ λ e₂, throw (if use_first_ex then e₁ else e₂)

def lift_except {ε' : Type u} [monad_except ε m] [has_lift_t ε' ε] [monad m] {α : Type v} : except ε' α → m α
| (except.error e) := throw ↑e
| (except.ok a) := pure a
end monad_except

export monad_except (throw catch)
Expand Down Expand Up @@ -167,3 +172,7 @@ end

instance (ε m out) [monad_run out m] : monad_run (λ α, out (except ε α)) (except_t ε m) :=
⟨λ α, run ∘ except_t.run⟩

-- useful for implicit failures in do-notation
instance (m) [monad m] : monad_fail (except_t string m) :=
⟨λ _, throw⟩
2 changes: 1 addition & 1 deletion library/init/default.lean
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ Authors: Leonardo de Moura
prelude
import init.core init.control init.data.basic init.version
import init.function init.util init.coe init.wf init.meta
import init.meta.well_founded_tactics init.data
import init.meta.well_founded_tactics init.data init.io
Loading