{#measures} ============ Measuring Data Types -------------------- Measuring Data Types ==================== Recap ----- 1.
**Refinements:** Types + Predicates
2.
**Subtyping:** SMT Implication
Example: Lists --------------
\begin{code} data L a = N | C a (L a) \end{code} Example: Length of a List ------------------------- \begin{code} {-@ measure llen :: (L a) -> Int llen (N) = 0 llen (C x xs) = 1 + (llen xs) @-} \end{code}
LiquidHaskell *strengthens* data constructor types \begin{code}
data L a where N :: {v: L a | (llen v) = 0} C :: a -> xs:L a -> {v:L a | (llen v) = 1 + (llen xs)} \end{code}
Measures Are Uninterpreted -------------------------- \begin{code}
data L a where N :: {v: L a | (llen v) = 0} C :: a -> xs:L a -> {v:L a | (llen v) = 1 + (llen xs)} \end{code}
`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 x y. (x = y) => (f x) = (f y)`
All other facts about `llen` asserted at *fold* and *unfold*
Measures Are Uninterpreted -------------------------- All other facts about `llen` asserted at *fold* and *unfold*
\begin{code}**Fold**
z = C x y -- z :: {v | llen v = 1 + llen y} \end{code}

\begin{code}**Unfold**
case z of N -> e1 -- z :: {v | llen v = 0} C x y -> e2 -- z :: {v | llen v = 1 + llen y} \end{code}
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 indexed 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} List Indexing Redux ------------------- Now we can type list indexed lookup: \begin{code}
{-@ (!) :: xs:L a -> (LtLen xs) -> a @-} (C x _) ! 0 = x (C _ xs) ! i = xs ! (i - 1) _ ! _ = liquidError "never happens!" \end{code}
Demo: What if we *remove* the precondition? Multiple Measures ----------------- LiquidHaskell allows *many* measures for a type Multiple Measures ----------------- **Example:** Nullity of a `List` \begin{code} {-@ measure isNull :: (L a) -> Prop isNull (N) = true isNull (C x xs) = false @-} \end{code}
\begin{code} LiquidHaskell **strengthens** data constructors data L a where N :: {v : L a | (isNull v)} C :: a -> L a -> {v:(L a) | not (isNull v)} \end{code}
Multiple Measures ----------------- LiquidHaskell *conjoins* data constructor types: \begin{code}
data L a where N :: {v:L a | (llen v) = 0 && (isNull v) } C :: a -> xs:L a -> {v:L a | (llen v) = 1 + (llen xs) && not (isNull v) } \end{code} Multiple Measures ----------------- Unlike [indexed types](http://dl.acm.org/citation.cfm?id=270793) ...
+
Measures *decouple* properties from structures
+
Support *multiple* properties over structures
+
Enable *reuse* of structures

Invaluable in practice!
Refined Data Constructors ------------------------- Can *directly pack* properties inside data constructors

\begin{code} {-@ data L a = N | C (x :: a) (xs :: L {v:a | x <= v}) @-} \end{code}

Specifies *increasing* Lists
Refined Data Constructors ------------------------- **Example:** Increasing Lists, with strengthened constructors: \begin{code}
data L a where N :: L a C :: x:a -> xs: L {v:a | x <= v} -> L a \end{code}
-
LiquidHaskell *checks* property when *folding* `C`
-
LiquidHaskell *assumes* property when *unfolding* `C`
Refined Data Constructors ------------------------- Demo: Insertion Sort (hover for inferred types) \begin{code} insertSort = foldr insert N 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}
**Problem 1:** What if we need *both* [increasing and decreasing lists](http://web.cecs.pdx.edu/~sheard/Code/QSort.html)?
Recap ----- 1. **Refinements:** Types + Predicates 2. **Subtyping:** SMT Implication 3.
**Measures:** Strengthened Constructors
-
*Decouple* structure & property, enable *reuse*