packages feed

liquidhaskell-0.8.10.7: benchmarks/popl18/nople/pos/FoldrUniversal.hs

-- | Universal property of foldr a la Zombie
-- | cite : http://www.seas.upenn.edu/~sweirich/papers/congruence-extended.pdf

{-@ LIQUID "--reflection"     @-}

module FoldrUniversal where

import Prelude hiding (foldr)
import Language.Haskell.Liquid.ProofCombinators 

-- | foldrUniversal
{-@ reflect foldr @-}
foldr :: (a -> b -> b) -> b -> L a -> b
foldr f b xs
  | llen xs > 0
  = f (hd xs) (foldr f b (tl xs))
  | otherwise
  = b


{-@ foldrUniversal
      :: f:(a -> b -> b)
      -> h:(L a -> b)
      -> e:b
      -> ys:L a
      -> base:{h Emp == e }
      -> step: (x:a -> xs:L a -> {h (C x xs) == f x (h xs)})
      -> { h ys == foldr f e ys }
  @-}
foldrUniversal
    :: (a -> b -> b)
    -> (L a -> b)
    -> b
    -> L a
    -> Proof
    -> (a -> L a -> Proof)
    -> Proof
foldrUniversal f h e Emp base step
  =   h Emp
  === e               -- ? base
  === foldr f e Emp
  *** QED
foldrUniversal f h e (C x xs) base step
  =   h (C x xs)
      ? step x xs
  === f x (h xs)         
      ? foldrUniversal f h e xs base step
  === f x (foldr f e xs) 
  === foldr f e (C x xs)
  *** QED

-- | foldrFusion

{-@ foldrFusion :: h:(b -> c) -> f:(a -> b -> b) -> g:(a -> c -> c) -> e:b -> ys:L a
            -> fuse:(x:a -> y:b -> {h (f x y) == g x (h y)})
            -> { (compose h (foldr f e)) (ys) == foldr g (h e) ys }
  @-}
foldrFusion :: (b -> c) -> (a -> b -> b) -> (a -> c -> c) -> b -> L a
             -> (a -> b -> Proof)
             -> Proof
foldrFusion h f g e ys fuse
  = foldrUniversal g (compose h (foldr f e)) (h e) ys
       (fuse_base h f e)
       (fuse_step h f e g fuse)

fuse_step :: (b -> c) -> (a -> b -> b) -> b -> (a -> c -> c)
         -> (a -> b -> Proof)
         -> a -> L a -> Proof
{-@ fuse_step :: h:(b -> c) -> f:(a -> b -> b) -> e:b -> g:(a -> c -> c)
         -> thm:(x:a -> y:b -> { h (f x y) == g x (h y)})
         -> x:a -> xs:L a
         -> {(compose h (foldr f e)) (C x xs) == g x ((compose h (foldr f e)) (xs))}
  @-}
fuse_step h f e g thm x Emp
  =   (compose h (foldr f e)) (C x Emp)
  === h (foldr f e (C x Emp))
  === h (f x (foldr f e Emp))
  === h (f x e)
    ? thm x e
  === g x (h e) 
  === g x (h (foldr f e Emp))
  === g x ((compose h (foldr f e)) Emp)
  *** QED

fuse_step h f e g thm x (C y ys)
  =   (compose h (foldr f e)) (C x (C y ys))
  === h (foldr f e (C x (C y ys)))
  === h (f x (foldr f e (C y ys)))
  === h (f x (f y (foldr f e ys)))
    ? thm x (f y (foldr f e ys))
  === g x (h (f y (foldr f e ys)))
  === g x (h (foldr f e (C y ys)))
  === g x ((compose h (foldr f e)) (C y ys))
  *** QED

fuse_base :: (b->c) -> (a -> b -> b) -> b -> Proof
{-@ fuse_base :: h:(b->c) -> f:(a -> b -> b) -> e:b
              -> { (compose h (foldr f e)) (Emp) == h e } @-}
fuse_base h f e
  =   (compose h (foldr f e)) Emp
  === h (foldr f e Emp)
  === h e
  *** QED

{-@ reflect compose @-}
compose :: (b -> c) -> (a -> b) ->  a -> c
compose f g x = f (g x)

data L a = Emp | C a (L a)
{-@ data L [llen] @-}


{-@ measure llen @-}
llen :: L a -> Int
{-@ llen :: L a -> Nat @-}
llen Emp        = 0
llen (C _ xs) = 1 + llen xs

{-@ measure hd @-}
{-@ hd :: {v:L a | llen v > 0 } -> a @-}
hd :: L a -> a
hd (C x _) = x

{-@ measure tl @-}
{-@ tl :: xs:{L a | llen xs > 0 } -> {v:L a | llen v == llen xs - 1 } @-}
tl :: L a -> L a
tl (C _ xs) = xs