Abstract Refinements {#data} ============================ Recap ----- **So far** Abstract Refinements decouple invariants from + functions + indexed data
**Next** Decouple invariants from **recursive** data structures
Decouple Invariants From Data {#recursive} ========================================== {#asd} ------- Recursive Structures -------------------- Lets see another example of decoupling... Decouple Invariants From Recursive Data ======================================= Recall: Lists ------------- \begin{code} data L a = N | C { hd :: a, tl :: L a } \end{code} Recall: Refined Constructors ---------------------------- Define **increasing** Lists with strengthened constructors: \begin{spec}
data L a where N :: L a C :: hd:a -> tl: L {v:a | hd <= v} -> L a \end{spec} Problem: Decreasing Lists? -------------------------- What if we need *both* [increasing *and* decreasing lists?](http://hackage.haskell.org/package/base-4.7.0.0/docs/src/Data-List.html#sort)
Abstract That Refinement! ------------------------- \begin{code} {-@ data L a

a -> Prop> = N | C { hd :: a, tl :: L

a

} @-} \end{code}

`p` is a **binary relation** between two `a` values

Definition relates `hd` with **all** the elements of `tl`

Recursive: `p` holds for **every pair** of elements!
Example ------- Consider a list with *three* or more elements \begin{spec}
x1 `C` x2 `C` x3 `C` rest :: L

a \end{spec} Example: Unfold Once -------------------- \begin{spec}
x1 :: a x2 `C` x3 `C` rest :: L

a

\end{spec} Example: Unfold Twice --------------------- \begin{spec}
x1 :: a x2 :: a

x3 `C` rest :: L

a

\end{spec} Example: Unfold Thrice ---------------------- \begin{spec}
x1 :: a x2 :: a

x3 :: a

rest :: L

a

\end{spec}

Note how `p` holds between **every pair** of elements in the list.
A Concrete Example ------------------ That was a rather *abstract*!
How can we *use* fact that `p` holds between *every pair*?
**Instantiate** `p` with a *concrete* refinement
Example: Increasing Lists ------------------------- **Instantiate** `p` with a *concrete* refinement
\begin{code} {-@ type IncL a = L <{\hd v -> hd <= v}> a @-} \end{code}
Refinement says:   `hd` less than **every** `v` in tail,

i.e., `IncL` denotes **increasing** lists.
Example: Increasing Lists ------------------------- LiquidHaskell *verifies* that `slist` is indeed increasing... \begin{code} {-@ slist :: IncL Int @-} slist = 1 `C` 6 `C` 12 `C` N \end{code}
... and *protests* that `slist'` is not: \begin{code} {-@ slist' :: IncL Int @-} slist' = 6 `C` 1 `C` 12 `C` N \end{code}
Insertion Sort -------------- \begin{code} {-@ insertSort :: (Ord a) => [a] -> IncL a @-} insertSort = foldr insert N insert y N = y `C` N insert y (x `C` xs) | y < x = y `C` (x `C` xs) | otherwise = x `C` insert y xs \end{code}
(Mouseover `insert` to see inferred type.) Checking GHC Lists ------------------ Demo: Above applies to GHC's List definition: \begin{spec}
data [a]

a -> Prop> = [] | (:) { h :: a, tl :: [a

]

} \end{spec} Checking GHC Lists ------------------ Increasing Lists
\begin{code} {-@ type Incs a = [a]<{\h v -> h <= v}> @-} {-@ iGoUp :: Incs Int @-} iGoUp = [1,2,3] \end{code} Checking GHC Lists ------------------ Decreasing Lists
\begin{code} {-@ type Decs a = [a]<{\h v -> h >= v}> @-} {-@ iGoDn :: Decs Int @-} iGoDn = [3,2,1] \end{code} Checking GHC Lists ------------------ Duplicate-free Lists
\begin{code} {-@ type Difs a = [a]<{\h v -> h /= v}> @-} {-@ iDiff :: Difs Int @-} iDiff = [1,3,2] \end{code} Checking Lists -------------- Now we can check all the usual list sorting algorithms
Demo: List Sorting