Skip to content
Merged
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
53 changes: 38 additions & 15 deletions Linglib/Semantics/Composition/Continuation.lean
Original file line number Diff line number Diff line change
Expand Up @@ -57,27 +57,50 @@ def Cont.lower (m : Cont A A) : A := m id
abbrev Tower (C : Type u) (B : Type v) (A : Type w) := (A → B) → C

-- ════════════════════════════════════════════════════
-- § Monad Laws
-- § Monad instance
-- ════════════════════════════════════════════════════

/-- Left identity: `pure a >>= f = f a` -/
theorem Cont.bind_left_id (a : A) (f : A → Cont R B) :
Cont.bind (Cont.pure a) f = f a := rfl
/-! The continuation monad's laws (left/right identity, associativity, and the
functor laws) are exactly those of `LawfulMonad`, so we register `Cont R` as a
lawful monad rather than restating them as standalone `rfl` theorems. `R` is
fixed to `Type` (not universe-polymorphic) for Lean's `Monad` class. -/

/-- Right identity: `m >>= pure = m` -/
theorem Cont.bind_right_id (m : Cont R A) :
Cont.bind m Cont.pure = m := rfl
section Instances

/-- Associativity: `(m >>= f) >>= g = m >>= (λa. f a >>= g)` -/
theorem Cont.bind_assoc {C : Type*} (m : Cont R A) (f : A → Cont R B)
(g : B → Cont R C) :
Cont.bind (Cont.bind m f) g = Cont.bind m (λ a => Cont.bind (f a) g) := rfl
variable {R : Type}

/-- Map can be defined via bind and pure. -/
theorem Cont.map_via_bind (f : A → B) (m : Cont R A) :
Cont.map f m = Cont.bind m (λ a => Cont.pure (f a)) := rfl
instance : Functor (Cont R) where
map := Cont.map

/-- Lower of pure is identity. -/
instance : Pure (Cont R) where
pure := Cont.pure

instance : Bind (Cont R) where
bind := Cont.bind

instance : Seq (Cont R) where
seq mf mx := Cont.bind mf (λ f => Cont.map f (mx ()))

instance : Monad (Cont R) where

instance : LawfulMonad (Cont R) where
map_const := rfl
id_map _ := rfl
comp_map _ _ _ := rfl
bind_pure_comp _ _ := rfl
pure_bind _ _ := rfl
bind_assoc _ _ _ := rfl
bind_map _ _ := rfl
pure_seq _ _ := rfl
seq_pure _ _ := rfl
seq_assoc _ _ _ := rfl
seqLeft_eq _ _ := rfl
seqRight_eq _ _ := rfl
map_pure _ _ := rfl

end Instances

/-- Lower of pure is identity. (Not a monad law — a fact about `Cont.lower`.) -/
theorem Cont.lower_pure (a : A) : Cont.lower (Cont.pure a) = a := rfl

end Semantics.Composition.Continuation
42 changes: 4 additions & 38 deletions Linglib/Semantics/Composition/Effects.lean
Original file line number Diff line number Diff line change
Expand Up @@ -74,45 +74,11 @@ open Semantics.Montague
/-! ### §1 Typeclass instances for existing types

Register `Functor`, `Applicative`, and `Monad` instances for linglib's
`Cont R` and `Writer P` types, delegating to existing operations.
`Writer P` type, delegating to existing operations. The `Cont R` instances
live with the type in `Composition/Continuation.lean`.

Note: `Cont R A := (A → R) → R` requires `R : Type` (not
universe-polymorphic) for Lean's `Monad` class. -/

section ContInstances

variable {R : Type}

instance : Functor (Cont R) where
map := Cont.map

instance : Pure (Cont R) where
pure := Cont.pure

instance : Bind (Cont R) where
bind := Cont.bind

instance : Seq (Cont R) where
seq mf mx := Cont.bind mf (λ f => Cont.map f (mx ()))

instance : Monad (Cont R) where

instance : LawfulMonad (Cont R) where
map_const := rfl
id_map _ := rfl
comp_map _ _ _ := rfl
bind_pure_comp _ _ := rfl
pure_bind _ _ := rfl
bind_assoc _ _ _ := rfl
bind_map _ _ := rfl
pure_seq _ _ := rfl
seq_pure _ _ := rfl
seq_assoc _ _ _ := rfl
seqLeft_eq _ _ := rfl
seqRight_eq _ _ := rfl
map_pure _ _ := rfl

end ContInstances
Note: `Writer P` requires `P : Type` (not universe-polymorphic) for Lean's
`Monad` class. -/

section WriterInstances

Expand Down
121 changes: 39 additions & 82 deletions Linglib/Semantics/Dynamic/Effects/Probability.lean
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ The probabilistic effect models RSA-style soft assertion, threshold uncertainty,
and Bayesian update in dynamic semantics.

This file consolidates two former modules:
- Abstract probability-monad infrastructure (`ProbMonad`, `PState`, `CondProbMonad`,
`ChoiceProbMonad`, threshold semantics) — was `Dynamic/Probability/Basic.lean`
- Probability-monad infrastructure (`PState`, `CondProbMonad`, `ChoiceProbMonad`,
threshold semantics) built on mathlib's `Monad`/`LawfulMonad` — was
`Dynamic/Probability/Basic.lean`
- The `HasFiberedLookup PMF` instance and Bayesian-Charlow bridge —
was `Dynamic/Probability/Lookup.lean`

Expand Down Expand Up @@ -48,60 +49,18 @@ In Grove & White notation:
- `x ← m; k` is `bind m (λ x => k)`
-/

/--
Abstract probability monad interface.

A probability monad provides:
- `pure`: Lift a value to a trivial distribution
- `bind`: Sequence probabilistic computations
- Monad laws as equalities
/-!
### The probability monad is just a monad

This is the semantic interface; implementations may use PMFs, measures, etc.
A "probability monad" provides `pure`, `>>=`, and the three monad laws — i.e.
it is exactly mathlib's `Monad` / `LawfulMonad`, so we use those directly
rather than re-declaring the typeclass. `map`/`seq` and their functor laws are
mathlib's `Functor.map` / `id_map` / `comp_map`. The probability-*specific*
structure (conditioning, choice) is added on top by `CondProbMonad` /
`ChoiceProbMonad` below, which extend `[Monad P]`.

Note: We use Type instead of Type* to avoid universe issues. For semantic
work, this is typically sufficient.
`PMF` is the canonical instance (`Monad PMF` / `LawfulMonad PMF` in mathlib).
-/
class ProbMonad (P : Type → Type) where
/-- Trivial distribution concentrated at a value -/
pure : {α : Type} → α → P α
/-- Sequence: sample from m, then continue with k -/
bind : {α β : Type} → P α → (α → P β) → P β
/-- Left identity: `pure v >>= k = k v` -/
pure_bind : {α β : Type} → ∀ (v : α) (k : α → P β), bind (pure v) k = k v
/-- Right identity: `m >>= pure = m` -/
bind_pure : {α : Type} → ∀ (m : P α), bind m pure = m
/-- Associativity: `(m >>= n) >>= o = m >>= (λx. n x >>= o)` -/
bind_assoc : {α β γ : Type} → ∀ (m : P α) (n : α → P β) (o : β → P γ),
bind (bind m n) o = bind m (λ x => bind (n x) o)

namespace ProbMonad

variable {P : Type → Type} [ProbMonad P]
variable {α β γ : Type}

/-- Map a function over a distribution -/
def map (f : α → β) (m : P α) : P β :=
bind m (λ x => pure (f x))

/-- Sequence two distributions, ignoring the first result -/
def seq (m : P α) (n : P β) : P β :=
bind m (λ _ => n)

/-- Map preserves identity -/
theorem map_id (m : P α) : map (id : α → α) m = m := by
simp only [map]
exact bind_pure m

/-- Map composes -/
theorem map_comp (f : α → β) (g : β → γ) (m : P α) :
map g (map f m) = map (g ∘ f) m := by
simp only [map, Function.comp]
rw [bind_assoc]
congr 1
ext x
exact pure_bind (f x) (λ y => pure (g y))

end ProbMonad

-- ════════════════════════════════════════════════════════════════
-- § 2. Parameterized State Monad (Grove & White's `P^σ_σ' α`)
Expand Down Expand Up @@ -131,7 +90,7 @@ def PState (P : Type → Type) (σ σ' α : Type) := σ → P (α × σ')

namespace PState

variable {P : Type → Type} [ProbMonad P]
variable {P : Type → Type} [Monad P]
variable {σ σ' σ'' σ''' α β γ : Type}

/--
Expand All @@ -141,7 +100,7 @@ Returns the value paired with the unchanged state.
Grove & White: `⌜v⌝^σ = λs. ⌜(v, s)⌝`
-/
def pure (v : α) : PState P σ σ α :=
λ s => ProbMonad.pure (v, s)
λ s => Pure.pure (v, s)

/--
Bind for the parameterized state monad.
Expand All @@ -150,57 +109,53 @@ Sequences stateful-probabilistic computations, threading state through.
Grove & White: `do { x ← m; k x } = λs. (x, s') ← m(s); k(x)(s')`
-/
def bind (m : PState P σ σ' α) (k : α → PState P σ' σ'' β) : PState P σ σ'' β :=
λ s => ProbMonad.bind (m s) (λ ⟨x, s'⟩ => k x s')
λ s => (m s) >>= (λ ⟨x, s'⟩ => k x s')

/--
View (get) a component of the state.

Returns the value of applying `proj` to the current state, without modification.
-/
def view (proj : σ → α) : PState P σ σ α :=
λ s => ProbMonad.pure (proj s, s)
λ s => Pure.pure (proj s, s)

/--
Set (put) a component of the state.

Returns the new state created by `upd`, with a trivial value.
-/
def set (upd : σ → σ') : PState P σ σ' Unit :=
λ s => ProbMonad.pure ((), upd s)
λ s => Pure.pure ((), upd s)

/--
Modify the state in place.
-/
def modify (f : σ → σ) : PState P σ σ Unit :=
λ s => ProbMonad.pure ((), f s)
λ s => Pure.pure ((), f s)

variable [LawfulMonad P]

/--
Left identity for PState: `pure v >>= k = k v`
-/
theorem pure_bind (v : α) (k : α → PState P σ σ' β) :
bind (pure v) k = k v := by
funext s
simp only [bind, pure]
exact ProbMonad.pure_bind (v, s) (λ ⟨x, s'⟩ => k x s')
funext s; simp [bind, pure]

/--
Right identity for PState: `m >>= pure = m`
-/
theorem bind_pure (m : PState P σ σ' α) :
bind m pure = m := by
funext s
simp only [bind, pure]
conv_rhs => rw [← ProbMonad.bind_pure (m s)]
funext s; simp [bind, pure]

/--
Associativity for PState.
-/
theorem bind_assoc (m : PState P σ σ' α)
(n : α → PState P σ' σ'' β) (o : β → PState P σ'' σ''' γ) :
bind (bind m n) o = bind m (λ x => bind (n x) o) := by
funext s
simp only [bind]
rw [ProbMonad.bind_assoc]
funext s; simp [bind]

end PState

Expand All @@ -225,31 +180,33 @@ Extended probability monad with conditioning.

Adds `observe` for conditioning on boolean observations.
-/
class CondProbMonad (P : Type → Type) extends ProbMonad P where
class CondProbMonad (P : Type → Type) [Monad P] where
/-- The zero distribution (blocks all continuations) -/
fail : {α : Type} → P α
/-- Condition on a boolean: continue if true, block if false -/
observe : Bool → P Unit
/-- Observing true is a no-op -/
observe_true : observe true = pure ()
/-- Observing false blocks all continuations -/
observe_false_bind : {α : Type} → ∀ (k : Unit → P α), bind (observe false) k = fail
observe_false_bind : {α : Type} → ∀ (k : Unit → P α), (observe false >>= k) = fail
/-- fail is a left zero for bind -/
fail_bind : {α β : Type} → ∀ (k : α → P β), bind fail k = fail
fail_bind : {α β : Type} → ∀ (k : α → P β), (fail >>= k) = fail

namespace CondProbMonad

variable {P : Type → Type} [CondProbMonad P]

/-- Observe filters: observe true then return is identity -/
theorem observe_true_pure :
ProbMonad.bind (observe true) (λ _ => ProbMonad.pure (P := P) ()) = observe true := by
rw [observe_true, ProbMonad.pure_bind]
variable {P : Type → Type} [Monad P] [CondProbMonad P]

/-- Observe false blocks: any continuation after observe false gives fail -/
theorem observe_false_pure :
ProbMonad.bind (observe false) (λ _ => ProbMonad.pure (P := P) ()) = fail := by
exact observe_false_bind _
(observe false >>= (λ _ => (pure () : P Unit))) = fail :=
observe_false_bind _

variable [LawfulMonad P]

/-- Observe filters: observe true then return is identity -/
theorem observe_true_pure :
(observe true >>= (λ _ => (pure () : P Unit))) = observe true := by
rw [observe_true, pure_bind]

end CondProbMonad

Expand All @@ -276,20 +233,20 @@ Probability monad with choice (for speaker models).
Adds `choose` for sampling from weighted distributions.
This is what S1's softmax requires.
-/
class ChoiceProbMonad (P : Type → Type) extends CondProbMonad P where
class ChoiceProbMonad (P : Type → Type) [Monad P] extends CondProbMonad P where
/-- Sample from a weighted distribution over a finite type -/
choose : {α : Type} → [Fintype α] → (α → ℚ) → P α
/-- choose with uniform weights is like a uniform prior -/
choose_uniform : {α : Type} → [Fintype α] → [Nonempty α] →
choose (λ _ : α => 1) = choose (λ _ => 1) -- trivial, but states the interface
/-- choose then observe is like weighted observe -/
choose_observe : {α : Type} → [Fintype α] → ∀ (w : α → ℚ) (p : α → Bool),
bind (choose w) (λ a => bind (observe (p a)) (λ _ => pure a)) =
(choose w >>= (λ a => observe (p a) >>= (λ _ => pure a))) =
choose (λ a => w a * if p a then 1 else 0)

namespace ChoiceProbMonad

variable {P : Type → Type} [ChoiceProbMonad P]
variable {P : Type → Type} [Monad P] [ChoiceProbMonad P]
variable {α : Type} [Fintype α]

/--
Expand Down
Loading