{-# LANGUAGE TupleSections #-}
{-@ LIQUID "--no-warnings" @-}
{-@ LIQUID "--short-names" @-}
{-@ LIQUID "--no-termination" @-}
{- LIQUID "--totality" @-}
{-@ LIQUID "--diff" @-}
module AbstractRefinements (addElem, elems, length) where
import Prelude hiding (length)
import qualified Data.Set as S -- hiding (elems, insert)
isort :: (Ord a) => List a -> List a
insert :: (Ord a) => a -> List a -> List a
infixr 9 :::
{-@ measure elems @-}
elems :: (Ord a) => List a -> S.Set a
elems Emp = S.empty
elems (x:::xs) = S.union (S.singleton x) (elems xs)
{-@ inline addElem @-}
addElem :: (Ord a) => a -> List a -> S.Set a
addElem x xs = S.union (S.singleton x) (elems xs)
{-@ measure length @-}
length :: List a -> Int
length Emp = 0
length (_ ::: xs) = 1 + length xs
Abstract Refinements
Key Idea
Abstract The Property Away to make the specification Modular!
Then, instantiate the property back to get your specification.
Ordered Lists
Previously we saw how to refine the list data definition to get ordered lists:
{-@ data OList a =
OEmp
| (:<:) { oHd :: a
, oTl :: OList {v:a | oHd <= v}} @-}
Just abstract the property away!
Abstract Refinements on Data Structures
data List a
= Emp
| (:::) { hd :: a
, tl :: List a }
{-@ data List a < p :: a -> a -> Bool >
= Emp
| (:::) { hd :: a
, tl :: List < p > a< p hd > } @-}
-- a < p hd > stands for {v:a | p hd v}
Every element of the tail recursively satisfies p on the head!
Instantiation of Refinements
Unrefined Lists
{-@ type TList a = List <{\x v -> true }> a @-}
Increasing Lists
{-@ type OList a = List <{\x v -> x <= v}> a @-}
Decreasing Lists
{-@ type DList a = List <{\x v -> v <= x}> a @-}
Unique Lists
{-@ type UList a = List <{\x v -> x /= v}> a @-}
Using Abstract Refinements
Use increasing lists
{-@ type OList a = List <{\x v -> x <= v}> a @-}
to specify insertion sort, as before!
{-@ isort :: xs:List a -> OList a @-}
isort Emp = Emp
isort (x:::xs) = insert x (isort xs)
{-@ insert :: x:a -> xs:OList a
-> {v : OList a | length v == length xs + 1
&& elems v == addElem x xs } @-}
insert x (y ::: ys)
| x <= y = x ::: y ::: ys
| otherwise = y ::: insert x ys
insert x _ = x ::: Emp
Haskell's list
Haskell build-in list comes parameterized for you!
You can just instantiate the abstract refinement!
{-@ type IList a = [a]<{\x v -> (x <= v)}> @-}
And prove recursive list properties!
{-@ sort :: (Ord a) => [a] -> IList a @-}
sort :: (Ord a) => [a] -> [a]
sort = mergeAll . sequences
where
sequences (a:b:xs)
| a `compare` b == GT = descending b [a] xs
| otherwise = ascending b (a:) xs
sequences [x] = [[x]]
sequences [] = [[]]
{- descending :: x:a -> IList {v:a | x < v} -> [a] -> [IList a] @-}
descending a as (b:bs)
| a `compare` b == GT = descending b (a:as) bs
descending a as bs = (a:as): sequences bs
{- ascending :: x:a -> (IList {v:a|v>=x} -> IList a) -> [a] -> [IList a] @-}
ascending a as (b:bs)
| a `compare` b /= GT = ascending b (\ys -> as (a:ys)) bs
ascending a as bs = as [a]: sequences bs
mergeAll [x] = x
mergeAll xs = mergeAll (mergePairs xs)
mergePairs (a:b:xs) = merge1 a b: mergePairs xs
mergePairs [x] = [x]
mergePairs [] = []