Skip to content

Instantly share code, notes, and snippets.

@twanvl
Created December 21, 2013 23:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save twanvl/8076766 to your computer and use it in GitHub Desktop.
Save twanvl/8076766 to your computer and use it in GitHub Desktop.
Proof of confluence of beta reduction + D reduction (a simple form of eta for pairs), for the untyped lambda calculus. See http://lambda-the-ultimate.org/node/4835 for a discussion.
module 2013-11-13-relations where
open import Level hiding (zero;suc)
open import Function
open import Relation.Binary hiding (Sym)
open import Relation.Binary.PropositionalEquality as PE hiding (subst;sym;trans;refl)
open import Data.Empty
open import Data.Product using (∃)
open import Induction.WellFounded
--------------------------------------------------------------------------------
-- Utility
--------------------------------------------------------------------------------
Rel₀ : Set → Set₁
Rel₀ A = Rel A Level.zero
Arrow : ∀ {a b} → Set a → Set b → Set (a ⊔ b)
Arrow A B = A → B
Any : ∀ {a b r} {A : Set a} {B : Set b} → (A → Rel B r) → Rel B _
Any r u v = ∃ \x → r x u v
--------------------------------------------------------------------------------
-- Transitive closure
--------------------------------------------------------------------------------
module Star where
open import Data.Star public renaming (map to map'; fold to foldr)
map : ∀ {i j t u} {I : Set i} {T : Rel I t} {J : Set j} {U : Rel J u} →
{f : I → J} → T =[ f ]⇒ U → Star T =[ f ]⇒ Star U
map g xs = gmap _ g xs
concatMap : ∀ {i j t u}
{I : Set i} {J : Set j} {T : Rel I t} {U : Rel J u}
{f : I → J} → T =[ f ]⇒ Star U → Star T =[ f ]⇒ Star U
concatMap g xs = kleisliStar _ g xs
foldMap : ∀ {i j t p} {I : Set i} {J : Set j} {T : Rel I t}
{f : I → J} (P : Rel J p) →
Transitive P → Reflexive P → T =[ f ]⇒ P → Star T =[ f ]⇒ P
foldMap {f = f} P t r g = gfold f P (\a b → t (g a) b) r
fold : ∀ {a r} {A : Set a} {R : Rel A r} → {f : A → Set} → (R =[ f ]⇒ Arrow) → (Star R =[ f ]⇒ Arrow)
--fold {f = f} g = Data.Star.gfold f Arrow (\a b → b ∘ g a) id
fold {f = f} g = foldMap {f = f} Arrow (\f g x → g (f x)) id g
zip : ∀ {la lb lc r s t} {A : Set la} {B : Set lb} {C : Set lc} {R : Rel A r} {S : Rel B s} {T : Rel C t}
→ {f : A → B → C}
→ Reflexive R
→ Reflexive S
→ (∀ {a b c d} → R a b → S c d → T (f a c) (f b d))
→ ∀ {a b c d} → Star R a b → Star S c d → Star T (f a c) (f b d)
zip reflR reflS g xs ys = map (\x → g x reflS) xs ◅◅ map (\y → g reflR y) ys
open Star public using (Star;_◅_;_◅◅_;ε;_⋆)
--------------------------------------------------------------------------------
-- Non-Reflexive Transitive closure
--------------------------------------------------------------------------------
module Plus where
data Plus {l r} {A : Set l} (R : Rel A r) (a : A) (c : A) : Set (l ⊔ r) where
_◅_ : ∀ {b} → R a b → Star R b c → Plus R a c
plus-acc : ∀ {l} {A : Set l} {R : Rel A l} {x} → Acc (flip R) x → Acc (flip (Plus R)) x
plus-acc' : ∀ {l} {A : Set l} {R : Rel A l} {x y} → Acc (flip R) x → Plus R x y → Acc (flip (Plus R)) y
star-acc' : ∀ {l} {A : Set l} {R : Rel A l} {x y} → Acc (flip R) x → Star R x y → Acc (flip (Plus R)) y
plus-acc a = acc (\_ → plus-acc' a)
plus-acc' (acc a) (ab ◅ bc) = star-acc' (a _ ab) bc
star-acc' a ε = plus-acc a
star-acc' (acc a) (ab ◅ bc) = star-acc' (a _ ab) bc
well-founded : ∀ {l} {A : Set l} {R : Rel A l} → Well-founded (flip R) → Well-founded (flip (Plus R))
well-founded wf = plus-acc ∘ wf
open Plus public using (Plus;_◅_)
--------------------------------------------------------------------------------
-- Reflexive closure
--------------------------------------------------------------------------------
-- reflexive closure
module Refl where
data Refl {l r} {A : Set l} (R : Rel A r) (a : A) : A → Set (l ⊔ r) where
ε : Refl R a a
_◅ε : ∀ {b} → R a b → Refl R a b
_?◅_ : ∀ {l r} {A : Set l} {R : Rel A r} {x y z : A} → Refl R x y → Star R y z → Star R x z
ε ?◅ yz = yz
xy ◅ε ?◅ yz = xy ◅ yz
map : ∀ {la lb r s} {A : Set la} {B : Set lb} {R : Rel A r} {S : Rel B s}
→ {f : A → B}
→ (∀ {a b} → R a b → S (f a) (f b))
→ ∀ {a b} → Refl R a b → Refl S (f a) (f b)
map g ε = ε
map g (x ◅ε) = g x ◅ε
fromRefl : ∀ {a A r} {R : Rel {a} A r} → Reflexive R → Refl R ⇒ R
fromRefl refl ε = refl
fromRefl refl (x ◅ε) = x
open Refl public hiding (module Refl;map)
--------------------------------------------------------------------------------
-- Symmetric closure
--------------------------------------------------------------------------------
module Sym where
data CoSym {l r s} {A : Set l} (R : Rel A r) (S : Rel A s) (a : A) : A → Set (l ⊔ r ⊔ s) where
fwd : ∀ {b} → R a b → CoSym R S a b
bwd : ∀ {b} → S b a → CoSym R S a b
Sym : ∀ {l r} {A : Set l} (R : Rel A r) (a : A) → A → Set (l ⊔ r)
Sym R = CoSym R R
sym : ∀ {l r} {A : Set l} {R : Rel A r} {a b : A} → Sym R a b → Sym R b a
sym (fwd x) = bwd x
sym (bwd x) = fwd x
map : ∀ {la lb r s} {A : Set la} {B : Set lb} {R : Rel A r} {S : Rel B s}
→ {f : A → B}
→ (∀ {a b} → R a b → S (f a) (f b))
→ ∀ {a b} → Sym R a b → Sym S (f a) (f b)
map g (fwd x) = fwd (g x)
map g (bwd x) = bwd (g x)
open Sym public hiding (map;sym)
--------------------------------------------------------------------------------
-- Symmetric-transitive closure
--------------------------------------------------------------------------------
module StarSym where
StarSym : ∀ {l r} {A : Set l} (R : Rel A r) → Rel A (l ⊔ r)
StarSym R = Star (Sym R)
map : ∀ {la lb r s} {A : Set la} {B : Set lb} {R : Rel A r} {S : Rel B s}
→ {f : A → B}
→ (∀ {a b} → R a b → S (f a) (f b))
→ ∀ {a b} → StarSym R a b → StarSym S (f a) (f b)
map g = Star.map (Sym.map g)
zip : ∀ {la lb lc r s t} {A : Set la} {B : Set lb} {C : Set lc} {R : Rel A r} {S : Rel B s} {T : Rel C t}
→ {f : A → B → C}
→ Reflexive R
→ Reflexive S
→ (∀ {a b c d} → R a b → S c d → T (f a c) (f b d))
→ ∀ {a b c d} → StarSym R a b → StarSym S c d → StarSym T (f a c) (f b d)
zip reflR reflS g xs ys = map (\x → g x reflS) xs ◅◅ map (\y → g reflR y) ys
sym : ∀ {l r A R} → StarSym {l} {r} {A} R ⇒ flip (StarSym R)
sym = Star.reverse Sym.sym
into : ∀ {l r A R} → Sym (Star R) ⇒ StarSym {l} {r} {A} R
into (fwd xs) = Star.map fwd xs
into (bwd xs) = Star.reverse bwd xs
symInto : ∀ {l r A R} → Sym (StarSym R) ⇒ StarSym {l} {r} {A} R
symInto (fwd xs) = xs
symInto (bwd xs) = sym xs
concat : ∀ {l r A R} → StarSym (StarSym {l} {r} {A} R) ⇒ StarSym R
concat = Star.concat ∘ Star.map symInto
concatMap : ∀ {la lb r s} {A : Set la} {B : Set lb} {R : Rel A r} {S : Rel B s}
→ {f : A → B}
→ (∀ {a b} → R a b → StarSym S (f a) (f b))
→ ∀ {a b} → StarSym R a b → StarSym S (f a) (f b)
concatMap g = Star.concat ∘ Star.map (symInto ∘ Sym.map g)
concatMap' : ∀ {la lb r s} {A : Set la} {B : Set lb} {R : Rel A r} {S : Rel B s}
→ {f : A → B}
→ (∀ {a b} → R a b → Star S (f a) (f b))
→ ∀ {a b} → StarSym R a b → StarSym S (f a) (f b)
concatMap' g = Star.concat ∘ Star.map (into ∘ Sym.map g)
open StarSym public using (StarSym)
--------------------------------------------------------------------------------------------------
-- Relations
--------------------------------------------------------------------------------------------------
module Relations where
-- Here are some lemmas about confluence
-- First the generic stuff
infix 3 _||_
record CommonReduct' {la lb lc r s} {A : Set la} {B : Set lb} {C : Set lc}
(R : REL A C r) (S : REL B C s)
(a : A) (b : B) : Set (la ⊔ lb ⊔ lc ⊔ r ⊔ s) where
constructor _||_
field {c} : C
field reduce₁ : R a c
field reduce₂ : S b c
module CommonReduct where
CommonReduct : ∀ {a r} {A : Set a} (R : Rel A r) → Rel A (a ⊔ r)
CommonReduct R = CommonReduct' R R
maps : ∀ {a b c d e f r s t u} {A : Set a} {B : Set b} {C : Set c} {D : Set d} {E : Set e} {F : Set f}
{R : REL A C r} {S : REL B C s} {T : REL D F t} {U : REL E F u}
{f : A → D} {g : B → E} {h : C → F}
→ (∀ {u v} → R u v → T (f u) (h v))
→ (∀ {u v} → S u v → U (g u) (h v))
→ (∀ {u v} → CommonReduct' R S u v → CommonReduct' T U (f u) (g v))
maps f g (u || v) = f u || g v
map : ∀ {a b r s} {A : Set a} {B : Set b} {R : Rel A r} {S : Rel B s}
→ {f : A → B}
→ (R =[ f ]⇒ S) → (CommonReduct R =[ f ]⇒ CommonReduct S)
map g (u || v) = g u || g v
zips : ∀ {a b c d e f g h i r s t u v w}
{A : Set a} {B : Set b} {C : Set c} {D : Set d} {E : Set e} {F : Set f} {G : Set g} {H : Set h} {I : Set i}
{R : REL A C r} {S : REL B C s} {T : REL D F t} {U : REL E F u} {V : REL G I v} {W : REL H I w}
{f : A → D → G} {g : B → E → H} {h : C → F → I}
→ (∀ {x y u v} → R x y → T u v → V (f x u) (h y v))
→ (∀ {x y u v} → S x y → U u v → W (g x u) (h y v))
→ (∀ {x y u v} → CommonReduct' R S x y → CommonReduct' T U u v → CommonReduct' V W (f x u) (g y v))
zips f g (x || y) (u || v) = f x u || g y v
zip : ∀ {a b c r s t} {A : Set a} {B : Set b} {C : Set c} {R : Rel A r} {S : Rel B s} {T : Rel C t}
→ {f : A → B → C}
→ (f Preserves₂ R ⟶ S ⟶ T)
→ (f Preserves₂ CommonReduct R ⟶ CommonReduct S ⟶ CommonReduct T)
zip f (ac || bc) (df || ef) = f ac df || f bc ef
swap : ∀ {a r} {A : Set a} {R S : Rel A r}
→ ∀ {x y} → CommonReduct' R S x y → CommonReduct' S R y x
swap (u || v) = v || u
open CommonReduct public using (CommonReduct)
module CR = CommonReduct
GenConfluent : ∀ {a r s t u} {A : Set a} (R : Rel A r) (S : Rel A s) (T : Rel A t) (U : Rel A u)
→ Set (a ⊔ r ⊔ s ⊔ t ⊔ u)
GenConfluent R S T U = ∀ {a b c} → R a b → S a c → CommonReduct' T U b c
-- With two relations
CoConfluent : ∀ {a r s} {A : Set a} (R : Rel A r) (S : Rel A s) → Set (a ⊔ r ⊔ s)
CoConfluent R S = GenConfluent R S S R
SemiCoConfluent : ∀ {a r s} {A : Set a} (R : Rel A r) (S : Rel A s) → Set (a ⊔ r ⊔ s)
SemiCoConfluent R S = GenConfluent R (Star S) (Star S) (Star R)
HalfCoConfluent : ∀ {a r s} {A : Set a} (R : Rel A r) (S : Rel A s) → Set (a ⊔ r ⊔ s)
HalfCoConfluent R S = GenConfluent R S (Star S) R
StrongCoConfluent : ∀ {a r s} {A : Set a} (R : Rel A r) (S : Rel A s) → Set (a ⊔ r ⊔ s)
StrongCoConfluent R S = GenConfluent R (Star S) (Star S) (Refl R)
StrongerCoConfluent : ∀ {a r s} {A : Set a} (R : Rel A r) (S : Rel A s) → Set (a ⊔ r ⊔ s)
StrongerCoConfluent R S = GenConfluent R (Star S) (Star S) R
ReflCoConfluent : ∀ {a r s} {A : Set a} (R : Rel A r) (S : Rel A s) → Set (a ⊔ r ⊔ s)
ReflCoConfluent R S = GenConfluent R S (Refl S) (Refl R)
GlobalCoConfluent : ∀ {a r s} {A : Set a} (R : Rel A r) (S : Rel A s) → Set (a ⊔ r ⊔ s)
GlobalCoConfluent R S = CoConfluent (Star R) (Star S)
-- Now with a single relation
Confluent : ∀ {a r} {A : Set a} (R : Rel A r) → Set (a ⊔ r)
Confluent R = GenConfluent R R R R
LocalConfluent : ∀ {a r} {A : Set a} (R : Rel A r) → Set (a ⊔ r)
LocalConfluent R = GenConfluent R R (Star R) (Star R)
ReflConfluent : ∀ {a r} {A : Set a} (R : Rel A r) → Set (a ⊔ r)
ReflConfluent R = GenConfluent R R (Refl R) (Refl R)
SemiConfluent : ∀ {a r} {A : Set a} (R : Rel A r) → Set (a ⊔ r)
SemiConfluent R = GenConfluent R (Star R) (Star R) (Star R)
GlobalConfluent : ∀ {a r} {A : Set a} (R : Rel A r) → Set (a ⊔ r)
GlobalConfluent R = Confluent (Star R)
--StrongConfluent : ∀ {a r} {A : Set a} (R : Rel A r) → Set (a ⊔ r)
--StrongConfluent R = GenConfluent R R (Star R) (MaybeRel R)
-- semi confluence implies confluence for R*
SemiConfluent-to-GlobalConfluent : ∀ {a r s A} {R : Rel {a} A r} {S : Rel {a} A s} → SemiCoConfluent R S → GlobalCoConfluent R S
SemiConfluent-to-GlobalConfluent conf ε ab = ab || ε
SemiConfluent-to-GlobalConfluent conf ab ε = ε || ab
SemiConfluent-to-GlobalConfluent conf (ab ◅ bc) ad with conf ab ad
... | be || de with SemiConfluent-to-GlobalConfluent conf bc be
... | cf || ef = cf || (de ◅◅ ef)
Confluent-to-StrongConfluent : ∀ {a r s A} {R : Rel {a} A r} {S : Rel {a} A s} → CoConfluent R S → StrongCoConfluent R S
Confluent-to-StrongConfluent conf ab ε = ε || (ab ◅ε)
Confluent-to-StrongConfluent conf ab (ac ◅ cd) with conf ab ac
... | be || ce with Confluent-to-StrongConfluent conf ce cd
... | ef || df = be ◅ ef || df
Confluent-to-StrongerConfluent : ∀ {a r s A} {R : Rel {a} A r} {S : Rel {a} A s} → CoConfluent R S → StrongerCoConfluent R S
Confluent-to-StrongerConfluent conf ab ε = ε || ab
Confluent-to-StrongerConfluent conf ab (ac ◅ cd) with conf ab ac
... | be || ce with Confluent-to-StrongerConfluent conf ce cd
... | ef || df = be ◅ ef || df
HalfConfluent-to-StrongerConfluent : ∀ {a r s A} {R : Rel {a} A r} {S : Rel {a} A s} → HalfCoConfluent R S → StrongerCoConfluent R S
HalfConfluent-to-StrongerConfluent conf ab ε = ε || ab
HalfConfluent-to-StrongerConfluent conf ab (ac ◅ cd) with conf ab ac
... | be || ce with HalfConfluent-to-StrongerConfluent conf ce cd
... | ef || df = be ◅◅ ef || df
-- note: could be weakened to require StrongConfluent
Confluent-to-SemiConfluent : ∀ {a r s A} {R : Rel {a} A r} {S : Rel {a} A s} → CoConfluent R S → SemiCoConfluent R S
Confluent-to-SemiConfluent conf ab ε = ε || (ab ◅ ε)
Confluent-to-SemiConfluent conf ab (ac ◅ cd) with conf ab ac
... | be || ce with Confluent-to-SemiConfluent conf ce cd
... | ef || df = be ◅ ef || df
ReflConfluent-to-SemiConfluent : ∀ {a r s A} {R : Rel {a} A r} {S : Rel {a} A s} → ReflCoConfluent R S → SemiCoConfluent R S
ReflConfluent-to-SemiConfluent conf ab ε = ε || (ab ◅ ε)
ReflConfluent-to-SemiConfluent conf ab (ac ◅ cd) with conf ab ac
... | be || ε = be ?◅ cd || ε
... | be || ce ◅ε with ReflConfluent-to-SemiConfluent conf ce cd
... | ef || df = be ?◅ ef || df
Confluent-Star : ∀ {a r s A} {R : Rel {a} A r} {S : Rel {a} A s} → CoConfluent R S → GlobalCoConfluent R S
Confluent-Star = SemiConfluent-to-GlobalConfluent ∘ Confluent-to-SemiConfluent
from-StarSym : ∀ {a r A} {R : Rel {a} A r} → GlobalConfluent R → Star (Sym R) ⇒ CommonReduct (Star R)
from-StarSym conf ε = ε || ε
from-StarSym conf (fwd ab ◅ bc) with from-StarSym conf bc
... | bd || cd = ab ◅ bd || cd
from-StarSym conf (bwd ba ◅ bc) with from-StarSym conf bc
... | bd || cd with conf (ba ◅ ε) bd
... | be || de = be || cd ◅◅ de
to-StarSym : ∀ {a r A} {R : Rel {a} A r} → CommonReduct (Star R) ⇒ Star (Sym R)
to-StarSym (xs || ys) = Star.map fwd xs ◅◅ Star.reverse bwd ys
-- strong normalization + local confluence implies global confluence
-- we can write SN R as Well-founded (flip R)
well-founded-confluent : ∀ {a A} {R : Rel {a} A a} → Well-founded (flip R) → LocalConfluent R → GlobalConfluent R
well-founded-confluent wf conf = acc-confluent conf (Plus.well-founded wf _)
where
acc-confluent : ∀ {a A} {R : Rel {a} A a} → LocalConfluent R → ∀ {a b c} → Acc (flip (Plus R)) a → Star R a b → Star R a c → CommonReduct (Star R) b c
acc-confluent conf _ ε ac = ac || ε
acc-confluent conf _ ab ε = ε || ab
acc-confluent conf (acc a) (ab ◅ bc) (ad ◅ de) with conf ab ad
... | bf || df with acc-confluent conf (a _ (ab ◅ ε)) bc bf
... | cg || fg with acc-confluent conf (a _ (ad ◅ ε)) de df
... | eh || fh with acc-confluent conf (a _ (ab ◅ bf)) fg fh
... | gi || hi = cg ◅◅ gi || eh ◅◅ hi
confluent-by : ∀ {a A r s} {R : Rel {a} A r} {S : Rel A s}
→ (S ⇒ R) → (R ⇒ S)
→ Confluent R → Confluent S
confluent-by toR fromR confR ab ac = CR.map fromR (confR (toR ab) (toR ac))
concatCR : ∀ {a r A} {R : Rel {a} A r} → GlobalConfluent R → StarSym (CommonReduct (Star R)) ⇒ CommonReduct (Star R)
concatCR conf ε = ε || ε
concatCR conf (fwd (ad || bd) ◅ bc) with concatCR conf bc
... | be || ce with conf bd be
... | df || ef = ad ◅◅ df || ce ◅◅ ef
concatCR conf (bwd (bd || ad) ◅ bc) with concatCR conf bc
... | be || ce with conf bd be
... | df || ef = ad ◅◅ df || ce ◅◅ ef
open Relations public
--------------------------------------------------------------------------------
-- Empty relation
--------------------------------------------------------------------------------
module Empty {a} {A : Set a} where
Empty : Rel A Level.zero
Empty _ _ = ⊥
confluent : Confluent Empty
confluent ()
--gconfluent : GlobalConfluent Empty
--gconfluent = {!!}
--------------------------------------------------------------------------------
-- Triple common reduction
--------------------------------------------------------------------------------
module CRPlus where
infix 3 _|[_]|_
record CommonReductPlus {l r A} (R : Rel {l} A r) a b c : Set (l ⊔ r) where
constructor _|[_]|_
field {d} : A
field reduce₁ : R a d
field reduce₂ : R b d
field reduce₃ : R c d
toCR : CommonReduct R a c
toCR = reduce₁ || reduce₃
--fromCR : {l r A} {R : Rel {l} A r} {a b} → CommonReduct a b →
ConfluentPlus : ∀ {a r A} (R : Rel {a} A r) → Set (a ⊔ r)
ConfluentPlus R = ∀ {a b c} → R a b → R a c → CommonReductPlus R b a c
module 2013-12-21-confluence-beta-d where
open import 2013-11-13-relations
open import Function
open import Relation.Binary hiding (Sym)
open import Relation.Binary.PropositionalEquality as PE hiding (subst;sym;trans;refl)
open ≡-Reasoning
--------------------------------------------------------------------------------
-- Lambda calculus
--------------------------------------------------------------------------------
module Var where
-- The type (Var α) has one more element than the type α
-- it is isomorphic to Maybe α
data Var (α : Set) : Set where
zero : Var α
suc : α → Var α
-- Case analysis for Var
unvar : ∀ {α} {β : Var α → Set}
→ β zero → ((x : α) → β (suc x)) → (x : Var α) → β x
unvar z _ zero = z
unvar _ s (suc x) = s x
map : ∀ {α β} → (α → β) → Var α → Var β
map f = unvar zero (suc ∘ f)
one : ∀ {α} → Var (Var α)
one = suc zero
two : ∀ {α} → Var (Var (Var α))
two = suc one
open Var public hiding (map;module Var)
module Term where
data Term (A : Set) : Set where
var : (a : A) → Term A
lam : (a : Term (Var A)) → Term A
app : (a : Term A) → (b : Term A) → Term A
dup : (a : Term A) → (b : Term A) → Term A
-- T forms a functor
map : ∀ {A B} → (A → B) → Term A → Term B
map f (var a) = var (f a)
map f (lam x) = lam (map (Var.map f) x)
map f (app x y) = app (map f x) (map f y)
map f (dup x y) = dup (map f x) (map f y)
map-Term : ∀ {A B} → (A → Term B) → Var A → Term (Var B)
map-Term f = unvar (var zero) (map suc ∘ f)
-- and a monad
bind : ∀ {A B} → (A → Term B) → Term A → Term B
bind f (var a) = f a
bind f (lam x) = lam (bind (map-Term f) x)
bind f (app x y) = app (bind f x) (bind f y)
bind f (dup x y) = dup (bind f x) (bind f y)
-- we can use the monad for substitution
subst : ∀ {A} → Term (Var A) → Term A → Term A
subst a b = bind (unvar b var) a
-- We need these properties later on
-- these are all just standard functor and monad laws
module Properties where
-- properties of map, i.e. the functor laws
map-cong : ∀ {A B} {f g : A → B} → (f=g : ∀ x → f x ≡ g x) → (x : Term A) → map f x ≡ map g x
map-cong f=g (var x) = PE.cong var (f=g x)
map-cong f=g (lam x) = PE.cong lam (map-cong (unvar PE.refl (cong suc ∘ f=g)) x)
map-cong f=g (app x y) = PE.cong₂ app (map-cong f=g x) (map-cong f=g y)
map-cong f=g (dup x y) = PE.cong₂ dup (map-cong f=g x) (map-cong f=g y)
map-id : ∀ {A} → (x : Term A) → map id x ≡ x
map-id (var x) = PE.refl
map-id (lam x) = PE.cong lam (map-cong (unvar PE.refl (\_ → PE.refl)) x ⟨ PE.trans ⟩ map-id x)
map-id (app x y) = PE.cong₂ app (map-id x) (map-id y)
map-id (dup x y) = PE.cong₂ dup (map-id x) (map-id y)
map-map : ∀ {A B C} (f : B → C) (g : A → B) (x : Term A)
→ map f (map g x) ≡ map (f ∘ g) x
map-map f g (var x) = PE.refl
map-map f g (lam x) = PE.cong lam (map-map (Var.map f) (Var.map g) x
⟨ PE.trans ⟩ map-cong (unvar PE.refl (\_ → PE.refl)) x)
map-map f g (app x y) = PE.cong₂ app (map-map f g x) (map-map f g y)
map-map f g (dup x y) = PE.cong₂ dup (map-map f g x) (map-map f g y)
-- let's also prove some properties of the monad
bind-cong : ∀ {A B} {f g : A → Term B}
→ (f=g : ∀ x → f x ≡ g x) → (x : Term A) → bind f x ≡ bind g x
bind-cong f=g (var x) = f=g x
bind-cong f=g (lam x) = PE.cong lam (bind-cong (unvar PE.refl (PE.cong (map suc) ∘ f=g)) x)
bind-cong f=g (app x y) = PE.cong₂ app (bind-cong f=g x) (bind-cong f=g y)
bind-cong f=g (dup x y) = PE.cong₂ dup (bind-cong f=g x) (bind-cong f=g y)
bind-map : ∀ {A B} → (f : A → B) → (x : Term A) → bind (var ∘ f) x ≡ map f x
bind-map f (var x) = PE.refl
bind-map f (lam x) = PE.cong lam (bind-cong (unvar PE.refl (\_ → PE.refl)) x
⟨ PE.trans ⟩ bind-map (Var.map f) x)
bind-map f (app x y) = PE.cong₂ app (bind-map f x) (bind-map f y)
bind-map f (dup x y) = PE.cong₂ dup (bind-map f x) (bind-map f y)
bind-map₁ : ∀ {A B C} (f : B → Term C) (g : A → B) (x : Term A)
→ bind f (map g x) ≡ bind (f ∘ g) x
bind-map₁ f g (var x) = PE.refl
bind-map₁ f g (lam x) = PE.cong lam (bind-map₁ _ _ x
⟨ PE.trans ⟩ bind-cong (unvar PE.refl (\_ → PE.refl)) x)
bind-map₁ f g (app x y) = PE.cong₂ app (bind-map₁ f g x) (bind-map₁ f g y)
bind-map₁ f g (dup x y) = PE.cong₂ dup (bind-map₁ f g x) (bind-map₁ f g y)
bind-map₂ : ∀ {A B C} (f : B → C) (g : A → Term B) (x : Term A)
→ bind (map f ∘ g) x ≡ map f (bind g x)
bind-map₂ f g (var x) = PE.refl
bind-map₂ f g (lam x) = PE.cong lam (bind-cong (unvar PE.refl (lem ∘ g)) x
⟨ PE.trans ⟩ bind-map₂ _ _ x)
where
lem : ∀ y → map suc (map f y) ≡ map (Var.map f) (map suc y)
lem y = map-map _ _ y ⟨ PE.trans ⟩ PE.sym (map-map _ _ y)
bind-map₂ f g (app x y) = PE.cong₂ app (bind-map₂ f g x) (bind-map₂ f g y)
bind-map₂ f g (dup x y) = PE.cong₂ dup (bind-map₂ f g x) (bind-map₂ f g y)
bind-bind : ∀ {A B C} (f : B → Term C) (g : A → Term B) (x : Term A)
→ bind f (bind g x) ≡ bind (bind f ∘ g) x
bind-bind f g (var x) = PE.refl
bind-bind f g (lam x) = PE.cong lam (bind-bind _ _ x
⟨ PE.trans ⟩ bind-cong (unvar PE.refl (lem ∘ g)) x)
where
lem : ∀ y → bind (map-Term f) (map suc y) ≡ map suc (bind f y)
lem y = bind-map₁ _ _ y ⟨ PE.trans ⟩ bind-map₂ _ _ y
bind-bind f g (app x y) = PE.cong₂ app (bind-bind f g x) (bind-bind f g y)
bind-bind f g (dup x y) = PE.cong₂ dup (bind-bind f g x) (bind-bind f g y)
-- derived properties
bind-return : ∀ {A} → (x : Term A) → bind var x ≡ x
bind-return x = bind-map id x ⟨ PE.trans ⟩ map-id x
map-subst : ∀ {A B} (f : A → B) (a : Term (Var A)) (b : Term A)
→ map f (subst a b) ≡ subst (map (Var.map f) a) (map f b)
map-subst f a b
= PE.sym (bind-map₂ _ _ a)
⟨ PE.trans ⟩ bind-cong (unvar PE.refl \_ → PE.refl) a
⟨ PE.trans ⟩ PE.sym (bind-map₁ _ _ a)
bind-subst : ∀ {A B} (f : A → Term B) (a : Term (Var A)) (b : Term A)
→ bind f (subst a b) ≡ subst (bind (map-Term f) a) (bind f b)
bind-subst f a b
= bind-bind _ _ a ⟨ PE.trans ⟩
bind-cong (unvar PE.refl
(\x' → PE.sym (bind-return (f x')) ⟨ PE.trans ⟩
PE.sym (bind-map₁ (unvar (bind f b) var) suc (f x')))) a ⟨ PE.trans ⟩
PE.sym (bind-bind _ _ a)
open Properties public
open Term public hiding (map;bind;subst;module Term)
--------------------------------------------------------------------------------
-- Reduction
--------------------------------------------------------------------------------
data Beta {A} : Rel₀ (Term A) where
beta : ∀ {a b} → Beta (app (lam a) b) (Term.subst a b)
dup₁ : ∀ {a b} → StarSym Beta a b → Beta (dup a b) a
dup₂ : ∀ {a b} → StarSym Beta a b → Beta (dup a b) b
under-lam : ∀ {a a'} → Beta a a' → Beta (lam a) (lam a')
under-app₁ : ∀ {a a' b} → Beta a a' → Beta (app a b) (app a' b)
under-app₂ : ∀ {a b b'} → Beta b b' → Beta (app a b) (app a b')
under-dup₁ : ∀ {a a' b} → Beta a a' → Beta (dup a b) (dup a' b)
under-dup₂ : ∀ {a b b'} → Beta b b' → Beta (dup a b) (dup a b')
-- we want to prove confluence of Beta
--------------------------------------------------------------------------------
-- Simple dup rule
--------------------------------------------------------------------------------
data IStep {A} : Rel₀ (Term A) where
beta : ∀ {a b} → IStep (app (lam a) b) (Term.subst a b)
dup : ∀ {a} → IStep (dup a a) a
under-lam : ∀ {a a'} → IStep a a' → IStep (lam a) (lam a')
under-app : ∀ {a a' b b'} → IStep a a' → IStep b b' → IStep (app a b) (app a' b')
under-dup : ∀ {a a' b b'} → IStep a a' → IStep b b' → IStep (dup a b) (dup a' b')
under-var : ∀ {a} → IStep (var a) (var a)
irefl : ∀ {A} → Reflexive (IStep {A})
irefl {A} {var a} = under-var
irefl {A} {lam x} = under-lam irefl
irefl {A} {app x y} = under-app irefl irefl
irefl {A} {dup x y} = under-dup irefl irefl
-- isteps are preserved under map,bind,subst
map-istep : ∀ {A B} → (f : A → B) → IStep =[ Term.map f ]⇒ IStep
map-istep f (beta {a} {b}) rewrite map-subst f a b = beta
map-istep f dup = dup
map-istep f (under-lam x) = under-lam (map-istep _ x)
map-istep f (under-app x y) = under-app (map-istep f x) (map-istep f y)
map-istep f (under-dup x y) = under-dup (map-istep f x) (map-istep f y)
map-istep f under-var = under-var
bind-istep : ∀ {A B} (f : A → Term B) → IStep =[ Term.bind f ]⇒ IStep
bind-istep f (beta {a} {b}) rewrite bind-subst f a b = beta
bind-istep f dup = dup
bind-istep f (under-lam x) = under-lam (bind-istep _ x)
bind-istep f (under-app x y) = under-app (bind-istep f x) (bind-istep f y)
bind-istep f (under-dup x y) = under-dup (bind-istep f x) (bind-istep f y)
bind-istep f under-var = irefl
-- conversion
beta-to-isteps : ∀ {A} → Beta {A} ⇒ StarSym IStep
betas-to-isteps : ∀ {A} → StarSym (Beta {A}) ⇒ StarSym IStep
beta-to-isteps beta = fwd beta ◅ ε
beta-to-isteps (dup₁ x) = StarSym.map (\u → under-dup irefl u) (StarSym.sym $ betas-to-isteps x) ◅◅ fwd dup ◅ ε
beta-to-isteps (dup₂ x) = StarSym.map (\u → under-dup u irefl) (betas-to-isteps x) ◅◅ fwd dup ◅ ε
beta-to-isteps (under-lam x) = StarSym.map under-lam (beta-to-isteps x)
beta-to-isteps (under-app₁ x) = StarSym.map (\u → under-app u irefl) (beta-to-isteps x)
beta-to-isteps (under-app₂ x) = StarSym.map (\u → under-app irefl u) (beta-to-isteps x)
beta-to-isteps (under-dup₁ x) = StarSym.map (\u → under-dup u irefl) (beta-to-isteps x)
beta-to-isteps (under-dup₂ x) = StarSym.map (\u → under-dup irefl u) (beta-to-isteps x)
betas-to-isteps ε = ε
betas-to-isteps (fwd x ◅ xs) = beta-to-isteps x ◅◅ betas-to-isteps xs
betas-to-isteps (bwd x ◅ xs) = StarSym.sym (beta-to-isteps x) ◅◅ betas-to-isteps xs
istep-to-betas : ∀ {A} → IStep {A} ⇒ StarSym Beta
istep-to-betas beta = fwd beta ◅ ε
istep-to-betas dup = fwd (dup₁ ε) ◅ ε
istep-to-betas (under-lam x) = StarSym.map under-lam (istep-to-betas x)
istep-to-betas (under-app x y) = StarSym.map under-app₁ (istep-to-betas x) ◅◅
StarSym.map under-app₂ (istep-to-betas y)
istep-to-betas (under-dup x y) = StarSym.map under-dup₁ (istep-to-betas x) ◅◅
StarSym.map under-dup₂ (istep-to-betas y)
istep-to-betas under-var = ε
--------------------------------------------------------------------------------
-- Step: parallel beta reduction, and dup reduction guarded by IStep
--------------------------------------------------------------------------------
data Step {A} : Rel₀ (Term A) where
beta : ∀ {a a' b b'} → Step a a' → Step b b' → Step (app (lam a) b) (Term.subst a' b')
dup₁ : ∀ {a a' b} → StarSym IStep a b → Step a a' → Step (dup a b) a'
under-lam : ∀ {a a'} → Step a a' → Step (lam a) (lam a')
under-app : ∀ {a a' b b'} → Step a a' → Step b b' → Step (app a b) (app a' b')
under-dup : ∀ {a a' b b'} → Step a a' → Step b b' → Step (dup a b) (dup a' b')
under-var : ∀ {a} → Step (var a) (var a)
srefl : ∀ {A} → Reflexive (Step {A})
srefl {A} {var a} = under-var
srefl {A} {lam x} = under-lam srefl
srefl {A} {app x y} = under-app srefl srefl
srefl {A} {dup x y} = under-dup srefl srefl
-- conversion
istep-to-step : ∀ {A} → IStep {A} ⇒ Step
istep-to-step beta = beta srefl srefl
istep-to-step dup = dup₁ ε srefl
istep-to-step (under-lam x) = under-lam (istep-to-step x)
istep-to-step (under-app x y) = under-app (istep-to-step x) (istep-to-step y)
istep-to-step (under-dup x y) = under-dup (istep-to-step x) (istep-to-step y)
istep-to-step under-var = srefl
step-to-betas : ∀ {A} → Step {A} ⇒ Star Beta
step-to-betas (beta x y) = Star.map (under-app₁ ∘ under-lam) (step-to-betas x) ◅◅
Star.map under-app₂ (step-to-betas y) ◅◅ beta ◅ ε
step-to-betas (dup₁ x y) = dup₁ (StarSym.concatMap istep-to-betas x) ◅ step-to-betas y ◅◅ ε
step-to-betas (under-lam x) = Star.map under-lam (step-to-betas x)
step-to-betas (under-app x y) = Star.map under-app₁ (step-to-betas x) ◅◅ Star.map under-app₂ (step-to-betas y)
step-to-betas (under-dup x y) = Star.map under-dup₁ (step-to-betas x) ◅◅ Star.map under-dup₂ (step-to-betas y)
step-to-betas under-var = ε
step-to-isteps : ∀ {A} → Step {A} ⇒ StarSym IStep
step-to-isteps = Star.concatMap beta-to-isteps ∘ step-to-betas
-- steps are preserved under map,bind,subst
map-step : ∀ {A B} → (f : A → B) → Step =[ Term.map f ]⇒ Step
map-step f (beta {a' = a'} {b' = b'} x y) rewrite map-subst f a' b' = beta (map-step _ x) (map-step f y)
map-step f (dup₁ x y) = dup₁ (StarSym.map (map-istep f) x) (map-step f y)
map-step f (under-lam x) = under-lam (map-step _ x)
map-step f (under-app x y) = under-app (map-step f x) (map-step f y)
map-step f (under-dup x y) = under-dup (map-step f x) (map-step f y)
map-step f under-var = under-var
bind-step : ∀ {A B} {f g : A → Term B} (fg : ∀ x → Step (f x) (g x))
→ ∀ {x y} → Step x y → Step (Term.bind f x) (Term.bind g y)
bind-step {g = g} fg (beta {a' = a'} {b' = b'} x y) rewrite bind-subst g a' b' =
beta (bind-step (unvar srefl (map-step suc ∘ fg)) x) (bind-step fg y)
bind-step fg (dup₁ x y) = dup₁ (StarSym.map (bind-istep _) x) (bind-step fg y)
bind-step fg (under-lam x) = under-lam (bind-step (unvar srefl (map-step suc ∘ fg)) x)
bind-step fg (under-app x y) = under-app (bind-step fg x) (bind-step fg y)
bind-step fg (under-dup x y) = under-dup (bind-step fg x) (bind-step fg y)
bind-step fg under-var = fg _
subst-step : ∀ {A a a' b b'} → Step a a' → Step {A} b b' → Step (Term.subst a b) (Term.subst a' b')
subst-step aa bb = bind-step (unvar bb \_ → srefl) aa
-- confluence
sconfluent : ∀ {A} → Confluent (Step {A})
sconfluent under-var under-var = under-var || under-var
sconfluent (beta x y) (beta u v) = CR.zip subst-step (sconfluent x u) (sconfluent y v)
sconfluent (beta x y) (under-app (under-lam u) v) = CR.zips subst-step beta (sconfluent x u) (sconfluent y v)
sconfluent (under-app (under-lam x) y) (beta u v) = CR.zips beta subst-step (sconfluent x u) (sconfluent y v)
sconfluent (dup₁ x y) (dup₁ u v) = sconfluent y v
sconfluent (dup₁ x y) (under-dup u v) with sconfluent y u
... | y' || u' = y' || dup₁ (StarSym.sym (step-to-isteps u) ◅◅ x ◅◅ step-to-isteps v) u'
sconfluent (under-dup u v) (dup₁ x y) with sconfluent y u
... | y' || u' = dup₁ (StarSym.sym (step-to-isteps u) ◅◅ x ◅◅ step-to-isteps v) u' || y'
sconfluent (under-lam x) (under-lam u) = CR.map under-lam (sconfluent x u)
sconfluent (under-app x y) (under-app u v) = CR.zip under-app (sconfluent x u) (sconfluent y v)
sconfluent (under-dup x y) (under-dup u v) = CR.zip under-dup (sconfluent x u) (sconfluent y v)
isteps-to-steps : ∀ {A} → StarSym (IStep {A}) ⇒ CommonReduct (Star Step)
isteps-to-steps = from-StarSym (Confluent-Star sconfluent) ∘ StarSym.map istep-to-step
betas-to-steps : ∀ {A} → Star (Beta {A}) ⇒ CommonReduct (Star Step)
betas-to-steps = isteps-to-steps ∘ Star.concatMap beta-to-isteps
--------------------------------------------------------------------------------
-- Combined, we get confluence for beta+D
--------------------------------------------------------------------------------
beta-confluent : ∀ {A} → GlobalConfluent (Beta {A})
beta-confluent ab ac with betas-to-steps ab | betas-to-steps ac
... | ad || bd | ae || ce with Confluent-Star sconfluent ad ae
... | df || ef = Star.concatMap step-to-betas (bd ◅◅ df) || Star.concatMap step-to-betas (ce ◅◅ ef)
@delesley
Copy link

I found the following counter-example to eta-contraction of pairs:
http://www.seas.upenn.edu/~sweirich/types/archive/1991/msg00014.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment