packages feed

liquidhaskell-0.7.0.0: docs/slides/plpv14/hopa/AbstractRefinements.lhs

% Abstract Refinements

Abstract Refinements
--------------------

\begin{code}
module AbstractRefinements where
\end{code}


Abstract Refinements
--------------------

<br>

\begin{code} Consider the following function 
maxInt     :: Int -> Int -> Int 
maxInt x y = if x <= y then y else x 
\end{code}

<br>

\begin{code} We can give `maxInt` many (incomparable) refinement types:
maxInt :: Nat -> Nat -> Nat

maxInt :: Even -> Even -> Even

maxInt :: Prime -> Prime -> Prime
\end{code}

But **which** is the **right** type?


Parametric Invariants 
---------------------

`maxInt` returns *one of* its two inputs `x` and `y`. 

- **If** *both inputs* satisfy a property  

- **Then** *output* must satisfy that property

This holds, **regardless of what that property was!**
 
- That  is, we can **abstract over refinements**

- Or,  **parameterize** a type over its refinements.

Parametric Invariants
--------------------- 

\begin{code}
{-@ maxInt :: forall <p :: Int -> Prop>. Int<p> -> Int<p> -> Int<p> @-}
maxInt     :: Int -> Int -> Int 
maxInt x y = if x <= y then y else x 
\end{code}



Where

- `Int<p>` is just an abbreviation for `{v:Int | (p v)}`


This type states explicitly:

- **For any property** `p`, that is a property of `Int`, 

- `maxInt` takes two **inputs** of which satisfy `p`,

- `maxInt` returns an **output** that satisfies `p`. 


Parametric Invariants via Abstract Refinements
---------------------------------------------- 

\begin{code} We type `maxInt` as
maxInt :: forall <p :: Int -> Prop>. Int<p> -> Int<p> -> Int<p> 
\end{code}

We call `p` an an **abstract refinement** <br>


In the refinement logic,

- abstract refinements are **uninterpreted function symbols**

- which (only) satisfy the *congruence axiom*: forall x, y. x = y => (p x) = (p y)



Using Abstract Refinements
--------------------------

- **If** we call `maxInt` with two `Int`s with the same concrete refinement,

- **Then** the `p` will be instantiated with that concrete refinement,

- **The output** of the call will also enjoy the concrete refinement.

For example, the refinement is instantiated with `\v -> v >= 0` <br>

\begin{code}
{-@ maxNat :: Nat @-}
maxNat     :: Int
maxNat     = maxInt 2 5
\end{code}

Using Abstract Refinements
--------------------------

- **If** we call `maxInt` with two `Int`s with the same concrete refinement,

- **Then** the `p` will be instantiated with that concrete refinement,

- **The output** of the call will also enjoy the concrete refinement.

Or any other property <br>

\begin{code}
{-@ type RGB = {v: Int | ((0 <= v) && (v < 256)) } @-}
\end{code}

<br> to verify <br>

\begin{code}
{-@ maxRGB :: RGB @-}
maxRGB     :: Int
maxRGB     = maxInt 56 8
\end{code}