module DeBruijn where open import Prelude -- using (_∘_) -- composition, identity open import Data.Maybe open import Logic.Identity renaming (subst to subst≡) import Logic.ChainReasoning module Chain = Logic.ChainReasoning.Poly.Homogenous _≡_ (\x -> refl) (\x y z -> trans) open Chain -- untyped de Bruijn terms data Lam (A : Set) : Set where var : A -> Lam A app : Lam A -> Lam A -> Lam A abs : Lam (Maybe A) -> Lam A -- functoriality of Lam lam : {A B : Set} -> (A -> B) -> Lam A -> Lam B lam f (var a) = var (f a) lam f (app t1 t2) = app (lam f t1) (lam f t2) lam f (abs r) = abs (lam (fmap f) r) -- lifting a substitution A -> Lam B under a binder lift : {A B : Set} -> (A -> Lam B) -> Maybe A -> Lam (Maybe B) lift f nothing = var nothing lift f (just a) = lam just (f a) -- extensionality of lifting liftExt : {A B : Set}(f g : A -> Lam B) -> ((a : A) -> f a ≡ g a) -> (t : Maybe A) -> lift f t ≡ lift g t liftExt f g H nothing = refl liftExt f g H (just a) = cong (lam just) $ H a -- simultaneous substitution subst : {A B : Set} -> (A -> Lam B) -> Lam A -> Lam B subst f (var a) = f a subst f (app t1 t2) = app (subst f t1) (subst f t2) subst f (abs r) = abs (subst (lift f) r) -- extensionality of subst substExt : {A B : Set}(f g : A -> Lam B) -> ((a : A) -> f a ≡ g a) -> (t : Lam A) -> subst f t ≡ subst g t substExt f g H (var a) = H a substExt f g H (app t1 t2) = chain> subst f (app t1 t2) === app (subst f t1) (subst f t2) by refl === app (subst g t1) (subst f t2) by cong (\ x -> app x (subst f t2)) (substExt f g H t1) === app (subst g t1) (subst g t2) by cong (\ x -> app (subst g t1) x) (substExt f g H t2) substExt f g H (abs r) = chain> subst f (abs r) === abs (subst (lift f) r) by refl === abs (subst (lift g) r) by cong abs (substExt (lift f) (lift g) (liftExt f g H) r) === subst g (abs r) by refl -- Lemma: lift g ∘ fmap f = lift (g ∘ f) liftLaw1 : {A B C : Set}(f : A -> B)(g : B -> Lam C)(t : Maybe A) -> lift g (fmap f t) ≡ lift (g ∘ f) t liftLaw1 f g nothing = chain> lift g (fmap f nothing) === lift g nothing by refl === var nothing by refl === lift (g ∘ f) nothing by refl liftLaw1 f g (just a) = chain> lift g (fmap f (just a)) === lift g (just (f a)) by refl === lam just (g (f a)) by refl === lift (g ∘ f) (just a) by refl -- Lemma: subst g (lam f t) = subst (g ∘ f) t substLaw1 : {A B C : Set}(f : A -> B)(g : B -> Lam C)(t : Lam A) -> subst g (lam f t) ≡ subst (g ∘ f) t substLaw1 f g (var a) = refl substLaw1 f g (app t1 t2) = chain> subst g (lam f (app t1 t2)) === subst g (app (lam f t1) (lam f t2)) by refl === app (subst g (lam f t1)) (subst g (lam f t2)) by refl === app (subst (g ∘ f) t1) (subst g (lam f t2)) by cong (\ x -> app x (subst g (lam f t2))) (substLaw1 f g t1) === app (subst (g ∘ f) t1) (subst (g ∘ f) t2) by cong (\ x -> app (subst (g ∘ f) t1) x) (substLaw1 f g t2) substLaw1 f g (abs r) = chain> subst g (lam f (abs r)) === subst g (abs (lam (fmap f) r)) by refl === abs (subst (lift g) (lam (fmap f) r)) by refl === abs (subst (lift g ∘ fmap f) r) by cong abs (substLaw1 (fmap f) (lift g) r) === abs (subst (lift (g ∘ f)) r) by cong abs (substExt (lift g ∘ fmap f) (lift (g ∘ f)) (liftLaw1 f g) r) -- Lemma: subst (lam f ∘ g) = lam f ∘ subst g substLaw2 : {A B C : Set}(f : B -> C)(g : A -> Lam B)(t : Lam A) -> subst (lam f ∘ g) t ≡ lam f (subst g t) substLaw2 f g (var a) = refl