[Agda] Termination proof in partiality monad
Dan Doel
dan.doel at gmail.com
Thu Nov 20 01:15:46 CET 2008
All right. In light of the input (I didn't realize I was bumping into the same
old usual problem with codata), I've reformulated the proofs into something
more akin to Anton Setzer's coalgebraic approach, and got something that types
now. Enjoy (Prelim again contains Nat and Sigma):
--------------------------------------------------------------------------------
module Partial where
data _⊎_ (a b : Set) : Set where
inl : a -> a ⊎ b
inr : b -> a ⊎ b
codata D (a : Set) : Set where
now : a -> D a
later : D a -> D a
_⋆ : {a : Set} -> D a -> a ⊎ D a
now a ⋆ = inl a
later da ⋆ = inr da
never : {a : Set} -> D a
never ~ later never
return : {a : Set} -> a -> D a
return x = now x
infixl 40 _>>=_
_>>=_ : {a b : Set} -> D a -> (a -> D b) -> D b
da >>= f with da ⋆
... | inl a ~ f a
... | inr da' ~ later (da' >>= f)
map-D : {a b : Set} -> (a -> b) -> D a -> D b
map-D f da with da ⋆
... | inl a ~ now (f a)
... | inr da' ~ later (map-D f da')
fix-aux : {a b : Set} (k : a -> D b) (f : (a -> D b) -> a -> D b) -> a -> D b
fix-aux k f a with f k a ⋆
... | inl v ~ now v
... | inr _ ~ later (fix-aux (f k) f a)
fix : {a b : Set} (f : (a -> D b) -> a -> D b) -> a -> D b
fix = fix-aux (\_ -> never)
--------------------------------------------------------------------------------
module Convergence where
open import Prelim
open import Partial
mutual
infix 35 _↓_
_↓_ : {a : Set} -> D a -> a -> Set
dx ↓ v with dx ⋆
... | inl x = ConvergeNow x v
... | inr dx' = ConvergeLater dx' v
data ConvergeNow {a : Set} (x : a) : a -> Set where
converge-now : ConvergeNow x x
data ConvergeLater {a : Set} (dx : D a) (v : a) : Set where
converge-later : dx ↓ v -> ConvergeLater dx v
_↓ : {a : Set} -> D a -> Set
_↓ {a} dx = Σ a (_↓_ dx)
map-D-↓ : {a b : Set}{dx : D a}{v : a} (f : a -> b) -> dx ↓ v -> map-D f dx ↓
f v
map-D-↓ {a}{b}{dx} f pf with dx ⋆
map-D-↓ {a} {b} {dx} {v} f converge-now | inl .v = converge-now
map-D-↓ f (converge-later pf) | inr y = converge-later (map-
D-↓ f pf)
-- Sorry this isn't so pretty. This isn't ever used anywhere, but it may be
-- instructive I suppose.
>>=-↓ : {a b : Set} {dx : D a}{v : a}{v' : b}
(f : a -> D b) -> dx ↓ v -> f v ↓ v' -> dx >>= f ↓ v'
>>=-↓ {a}{b}{dx} f pfa pfb with dx ⋆
>>=-↓ {a}{b}{dx}{v} f converge-now pfb | inl .v with f v ⋆
>>=-↓ {dx} {b} {_} {v} {v'} f converge-now converge-now
| inl .v | inl .v' = converge-now
>>=-↓ f converge-now (converge-later pf) | inl .v | inr y = converge-later pf
>>=-↓ f (converge-later y) pfb | inr dx' = converge-later (>>=-↓ f y pfb)
--------------------------------------------------------------------------------
module Factorial where
open import Prelim
open import Partial
open import Convergence
fac-aux : (Nat -> D Nat) -> Nat -> D Nat
fac-aux _ zero = return 1
fac-aux fac (suc n) = map-D (_*_ (suc n)) (fac n)
fac : Nat -> D Nat
fac = fix fac-aux
fix-fac-ind : {g : Nat -> D Nat} {n k : Nat}
-> fix-aux g fac-aux n ↓ k
-> fix-aux (fac-aux g) fac-aux (suc n) ↓ suc n * k
fix-fac-ind {g} {n} pf with fac-aux g n ⋆
fix-fac-ind {g} {n} {k} converge-now | inl .k = converge-now
fix-fac-ind (converge-later pf) | inr y = converge-later (fix-fac-ind pf)
fac-↓ : forall {n} -> fac n ↓
fac-↓ {0} = 1 , converge-now
fac-↓ {suc n} with fac-↓ {n}
fac-↓ {suc n} | n! , pf-n!-↓
= (suc n * n! , converge-later (fix-fac-ind pf-n!-↓))
--------------------------------------------------------------------------------
And there you have it. A genuine proof of convergence for factorial that
passes the type checker. Proof for a version of fix that actually works
correctly is left as an exercise to the reader. :)
Cheers,
-- Dan
More information about the Agda
mailing list