[Agda] Termination proof in partiality monad

Dan Doel dan.doel at gmail.com
Tue Nov 18 21:43:36 CET 2008


Greetings.

I've been playing a bit with this since your initial mail, and thought I'd 
show you what I have so far. Unfortunately, I haven't found a way to prove 
termination of factorial defined with the fixed point combinator. However, a 
recursive factorial written directly in the partiality monad is fairly simple. 
Code follows. The module Prelim contains definitions for the natural numbers 
and sigma types. I split up the modules because otherwise Agda gobbles up all 
my memory. :)

------------------

module Partial where

codata D (a : Set) : Set where
  now   : (x : a)    -> D a
  later : (dx : D a) -> D a

never : {a : Set} -> D a
never ~ later never

return : {a : Set} -> a -> D a
return = now

infixl 40 _>>=_
_>>=_ : {a b : Set} -> D a -> (a -> D b) -> D b
now a    >>= f ~ f a
later da >>= f ~ later (da >>= f)

race : {a : Set} -> D a -> D a -> D a
race (now a)    _           ~ now a
race (later da) (now a)     ~ now a
race (later da) (later da') ~ later (race da da')

map-D : {a b : Set} -> (a -> b) -> D a -> D b
map-D f (now x)    ~ now (f x)
map-D f (later dx) ~ later (map-D f dx)

fix-aux : {a b : Set} -> (a -> D b) -> ((a -> D b) -> a -> D b) -> a -> D b
fix-aux k f a with f k a
...           | now b   ~ now b
...           | later d ~ later (fix-aux (f k) f a)

fix : {a b : Set} -> ((a -> D b) -> a -> D b) -> a -> D b
fix = fix-aux (\_ -> never)

------------------

module Convergence where

open import Prelim
open import Partial

mutual
  _↓_ : {a : Set} -> (x : D a) -> (v : a) -> Set
  now v    ↓ v' = ConvergeNow (now v) v'
  later dv ↓ v  = ConvergeLater dv v

  data ConvergeNow {a : Set} : D a -> a -> Set where
    converge-now : (x : a) -> ConvergeNow (now x) x

  data ConvergeLater {a : Set} (dv : D a) (v : a) : Set where
    converge-later : (pf : dv ↓ v) -> ConvergeLater dv 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}{now v}{.v} f (converge-now .v) = converge-now (f v)
map-D-↓ {a}{b}{later dv} {v} f (converge-later pf)
  = converge-later (map-D-↓ f pf)

>>=-↓ :  {a b : Set} {f : a -> D b} {dx : D a} {v : a} {v' : b}
      -> dx ↓ v -> f v ↓ v' -> (dx >>= f) ↓ v'
>>=-↓ {a}{b}{f}{now v}    (converge-now .v)   pf  = pf
>>=-↓ {a}{b}{f}{later dv} (converge-later pf) pf' 
    = converge-later (>>=-↓ pf pf')

------------------

module Factorial where

open import Prelim
open import Partial
open import Convergence

-- A direct factorial
fac' : Nat -> D Nat
fac' 0       ~ return 1
fac' (suc n) ~ later (map-D (_*_ (suc n)) (fac' n))

fac'-↓ : forall {n} -> fac' n ↓
fac'-↓ {0}     = (1 , converge-now 1)
fac'-↓ {suc n} with fac'-↓ {n}
...            | (n! , pf-n!-↓) = let suc-n! = suc n * n!
                                      pf' = map-D-↓ (_*_ (suc n)) pf-n!-↓
                                  in (suc-n! , converge-later pf')

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

fac-↓ : forall {n} -> fac n ↓
fac-↓ {0}     = (1 , converge-now 1)
fac-↓ {suc n} with fac-↓ {n}
...           | (n! , pf-n!-↓) = let suc-n! = suc n * n!
                                     pf' = map-D-↓ (_*_ (suc n)) pf-n!-↓
                                  in (suc-n! , converge-later ?  )

------------------

So, there you have it so far. fac'-↓ is a relatively easy proof. I've tried a 
similar scheme for fac-↓, but get stuck in the inductive case. The blank needs 
to be filled with something of type:

    fix-aux (fac-aux (\_ -> never)) fac-aux (suc n) ↓ n! + n * n!

And my pf' is merely an:

    map-D (_*_ (suc n)) (fix-aux (\_ -> never) fac-aux n ↓ n! + n * n!

Which looks like an unfolding issue, but probably one that's complex enough to 
require some lemmas to work through.

On a related note, I'm seeing things like this in my lower buffer:

   fix-aux (\_ -> never) fac-aux n | fac-aux (\_ -> never) n)

(In the 'type' in the error message for instance). What does 'foo | bar' mean? 
I don't recall ever seeing that before.

Cheers,
-- Dan


More information about the Agda mailing list