\begin{code}
{-# LIQUID "--no-termination" #-}
{-# LIQUID "--full" #-}
module Measures where
import Prelude hiding ((!!), length)
import Language.Haskell.Liquid.Prelude
length :: L a -> Int
(!) :: L a -> Int -> a
insert :: Ord a => a -> L a -> L a
insertSort :: Ord a => [a] -> L a
infixr `C`
\end{code}
Measuring Data Types
====================
Recap
-----
1.
We can define the **length** as:
\begin{code}
{-@ measure llen :: (L a) -> Int
llen (N) = 0
llen (C x xs) = 1 + (llen xs) @-}
\end{code}
\begin{code}
{-@ data L [llen] a = N | C {hd :: a, tl :: L a } @-}
{-@ invariant {v: L a | 0 <= llen v} @-}
\end{code}
Example: Length of a List
-------------------------
\begin{spec}
{-@ measure llen :: (L a) -> Int
llen (N) = 0
llen (C x xs) = 1 + llen xs @-}
\end{spec}
We **strengthen** data constructor types
\begin{spec}
data L a where
N :: {v: L a | (llen v) = 0}
C :: a -> t:_ -> {v:_| llen v = 1 + llen t}
\end{spec}
Measures Are Uninterpreted
--------------------------
\begin{spec}
data L a where
N :: {v: L a | (llen v) = 0}
C :: a -> t:_ -> {v:_| llen v = 1 + llen t}
\end{spec}
`llen` is an **uninterpreted function** in SMT logic
Measures Are Uninterpreted
--------------------------
In SMT, [uninterpreted function](http://fm.csl.sri.com/SSFT12/smt-euf-arithmetic.pdf) $f$ obeys **congruence** axiom:
$$\forall \overline{x}, \overline{y}. \overline{x} = \overline{y} \Rightarrow
f(\overline{x}) = f(\overline{y})$$
Other properties of `llen` asserted when typing **fold** & **unfold**
Crucial for *efficient*, *decidable* and *predictable* verification.
Measures Are Uninterpreted
--------------------------
Other properties of `llen` asserted when typing **fold** & **unfold**
\begin{spec}**Fold**
z = C x y -- z :: {v | llen v = 1 + llen y}
\end{spec}
\begin{spec}**Unfold**
case z of
N -> e1 -- z :: {v | llen v = 0}
C x y -> e2 -- z :: {v | llen v = 1 + llen y}
\end{spec}
Measured Refinements
--------------------
Now, we can verify:
\begin{code}
{-@ length :: xs:L a -> EqLen xs @-}
length N = 0
length (C _ xs) = 1 + length xs
\end{code}
Where `EqLen` is a type alias:
\begin{code}
{-@ type EqLen Xs = {v:Nat | v = llen Xs} @-}
\end{code}
List Indexing Redux
-------------------
We can type list lookup:
\begin{code}
{-@ (!) :: xs:L a -> LtLen xs -> a @-}
(C x _) ! 0 = x
(C _ xs) ! i = xs ! (i - 1)
_ ! _ = liquidError "never happens!"
\end{code}
Where `LtLen` is a type alias:
\begin{code}
{-@ type LtLen Xs = {v:Nat | v < llen Xs} @-}
\end{code}
Demo:
What if we *remove* the precondition?
Multiple Measures
-----------------
**Multiple** measures by **conjoining** refinements.
e.g. Red Black Tree
+ Height
+ Color
+ Nodes, etc.
Refined Data Constructors
=========================
{#refined-data-cons}
---------------------
Can encode *other* invariants **inside constructors**
\begin{code}
{-@ data L a = N
| C { x :: a
, xs :: L {v:a| x <= v} } @-}
\end{code}
Head `x` is less than **every** element of tail `xs`
i.e. specifies **increasing** Lists
Increasing Lists
----------------
\begin{spec}
data L a where
N :: L a
C :: x:a -> xs: L {v:a | x <= v} -> L a
\end{spec}
-
We **check** property when **folding** `C`
-
We **assume** property when **unfolding** `C`
Increasing Lists
----------------
Demo: Insertion Sort (hover for inferred types)
\begin{code}
insertSort xs = foldr insert N xs
insert y (x `C` xs)
| y <= x = y `C` (x `C` xs)
| otherwise = x `C` insert y xs
insert y N = y `C` N
\end{code}
Recap
-----
1. Refinements: Types + Predicates
2. Subtyping: SMT Implication
3. **Measures:** Strengthened Constructors
Logic + Analysis for Collections