% Abstract Refinements
Abstract Refinements
--------------------
\begin{code}
module AbstractRefinements where
\end{code}
Abstract Refinements
--------------------
\begin{code} Consider the following function
maxInt :: Int -> Int -> Int
maxInt x y = if x <= y then y else x
\end{code}
\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
Prop>. Int
-> Int
-> Int
@-} maxInt :: Int -> Int -> Int maxInt x y = if x <= y then y else x \end{code} Where - `Int
` 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
Prop>. Int
-> Int
-> Int
\end{code}
We call `p` an an **abstract refinement**
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`
\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
\begin{code}
{-@ type RGB = {v: Int | ((0 <= v) && (v < 256)) } @-}
\end{code}
to verify
\begin{code}
{-@ maxRGB :: RGB @-}
maxRGB :: Int
maxRGB = maxInt 56 8
\end{code}