packages feed

MiniAgda-0.2014.1.9: test/succeed/CoFunReturnsProduct.ma

-- 2010-05-20, -06-08 Andreas Abel
-- breadth-first relabeling of possibly infinite trees (Jones and Gibbons, 1993)
-- see Nils Anders Danielsson, Beating the Productivity Checker (PAR 2010, FLoC)
-- 2012-01-22 parameters gone from constructors

data Prod (+ A : Set)(+ B : Set) : Set 
{ pair : (fst : A) -> (snd : B) -> Prod A B
} fields fst, snd

sized codata Stream (+ A : Set) : Size -> Set
{ cons : [i : Size] -> (head : A) -> (tail : Stream A i) -> Stream A ($ i)
} fields head, tail

sized codata Tree (+ A : Set) : Size -> Set 
{ leaf : [i : Size] -> Tree A ($ i)
; node : [i : Size] -> A -> Tree A i -> Tree A i -> Tree A ($ i)
}

-- this definition is fine since the result type is a product
-- where each of its components is coinductive in i (TLCA, 2003)
cofun lab : [i : Size] -> [A : Set] -> [B : Set] ->
   Tree A i -> Stream (Stream B #) i -> 
   Prod (Tree B i) (Stream (Stream B #) i)
{
  lab ($ i) A B (leaf {-.A-} .i) bss = 
    pair {- (Tree B ($ i)) (Stream (Stream B #) ($ i)) -} (leaf {-B-} i) bss

; lab ($ i) A B (node {-.A-} .i x l r) 
    (cons {- .(Stream B #) -} .i (cons {-.B-} .# b bs) bss) =

      -- recursive call on left subtree
      let    pl   : Prod (Tree B i) (Stream (Stream B #) i)
                  = lab i A B l bss 

      -- recursive call on right subtree, threading the label stream-stream
      in let pr   : Prod (Tree B i) (Stream (Stream B #) i)
                  = lab i A B r (snd {- (Tree B i) (Stream (Stream B #) i) -} pl) 

      in pair {- (Tree B ($ i)) (Stream (Stream B #) ($ i)) -}
           (node {-B-} i b (fst {- (Tree B i) (Stream (Stream B #) i) -} pl)
                       (fst {- (Tree B i) (Stream (Stream B #) i) -} pr))
           (cons {- (Stream B #) -} i bs 
                       (snd {- (Tree B i) (Stream (Stream B #) i) -} pr))
}


-- this auxiliary function replaces the original circular program
cofun label2 : [i : Size] -> [A : Set] -> [B : Set] -> 
  Tree A i -> Stream B # -> Stream (Stream B #) i 
{ label2 ($ i) A B t bs = snd {- (Tree B ($ i)) (Stream (Stream B #) ($ i)) -}
    (lab ($ i) A B t (cons {- (Stream B #)-} i bs (label2 i A B t bs)))
}

-- main program
fun label : [i : Size] -> [A : Set] -> [B : Set] -> 
  Tree A i -> Stream B # -> Tree B i
{ label i A B t bs = fst {- (Tree B i) (Stream (Stream B #) i) -}
   (lab i A B t (cons {-(Stream B #)-} i bs (label2 i A B t bs)))
}

-- testing...

data Unit : Set
{ unit : Unit
}

data Nat : Set 
{ Z : Nat
; S : Nat -> Nat
}

cofun nats : [i : Size] -> Nat -> Stream Nat i
{ nats ($ i) n = cons {-Nat-} i n (nats i (S n))
}

fun finTree : Nat -> Tree Unit #
{ finTree Z = leaf {- Unit -} #
; finTree (S n) = node {- Unit -} # unit (finTree n) (finTree n)
}

eval let t0 : Tree Nat # = label # Unit Nat (finTree Z) (nats # Z)
eval let t1 : Tree Nat # = label # Unit Nat (finTree (S Z)) (nats # Z)
eval let t2 : Tree Nat # = label # Unit Nat (finTree (S (S Z))) (nats # Z)
eval let t3 : Tree Nat # = label # Unit Nat (finTree (S (S (S Z)))) (nats # Z)