pisigma-0.1.0.3: examples/SubjectReduction.pi
-- Context:
-- Recursion with boxes
-- Thorsten Altenkirch
-- http://sneezy.cs.nott.ac.uk/fplunch/weblog/?p=104
Stream : Type;
Stream = [∞ Stream];
ticks : Stream;
ticks = [ticks];
Eq : (A : Type) → A → A → Type;
Eq = λ A x y → (P : A → Type) → P x → P y;
refl : (A : Type) → (x : A) → Eq A x x;
refl = λ A x P px → px;
unfold : Eq Stream ticks [ticks];
unfold = refl Stream ticks;
-- We can prove this variant of congruence for boxes:
cong : (xs ys : Stream) → Eq Stream xs ys →
Eq Stream [let zs : Stream = xs in zs]
[let zs : Stream = ys in zs];
cong = λ xs ys eq P p → eq (λ zs → P [let us : Stream = zs in us]) p;
-- This does not (obviously) break subject reduction, because the
-- following property can be proved using refl:
unfoldInContext : Eq Stream [let xs : Stream = ticks in xs]
[let xs : Stream = [ticks] in xs];
unfoldInContext = cong ticks [ticks] unfold;
unfoldInContext = refl Stream [let xs : Stream = ticks in xs];
-- Note also that unlimited unfolding is not possible (using refl):
-- unfoldTwiceInContext : Eq Stream [let xs : Stream = ticks in xs]
-- [let xs : Stream = [[ticks]] in xs];
-- unfoldTwiceInContext = refl Stream [let xs : Stream = ticks in xs];
-- However, we can move lets through boxes, so the idea from
-- Thorsten's blog post needs to be qualified.
letThroughBox : (xs : Stream) →
Eq Stream [let ys : Stream = xs in ys]
(let ys : Stream = xs in [ys]);
letThroughBox = λ xs → refl Stream [let ys : Stream = xs in ys];
letThrough2Boxes : (xs : Stream) →
Eq Stream [[let ys : Stream = xs in ys]]
(let ys : Stream = xs in [[ys]]);
letThrough2Boxes = λ xs → refl Stream [[let ys : Stream = xs in ys]];
anotherExample : (A : Type) → (x : A) →
Eq (∞ (∞ A)) [let y : A = x in [y]]
(let y : A = x in [[let z : A = y in z]]);
anotherExample = λ A x → refl (∞ (∞ A)) (let y : A = x in [[y]]);