\begin{code}
{-@ LIQUID "--no-termination" @-}
module SimpleRefinements where
import Language.Haskell.Liquid.Prelude
import Prelude hiding (abs, max)
-- boring haskell type sigs
zero :: Int
zero' :: Int
safeDiv :: Int -> Int -> Int
abs :: Int -> Int
\end{code}
Simple Refinement Types
=======================
Types + Predicates
------------------
Example: Integers equal to `0`
------------------------------
\begin{code}
{-@ type Zero = {v:Int | v = 0} @-}
{-@ zero :: Zero @-}
zero = 0
\end{code}
Refinement types via special comments `{-@ ... @-}`
[DEMO](../hs/000_Refinements.hs)
Refinements Are Predicates
==========================
From A Decidable Logic
----------------------
1. Expressions
2. Predicates
**Refinement Logic: QF-UFLIA**
Quant.-Free. Uninterpreted Functions and Linear Arithmetic
Expressions
-----------
\begin{spec}
e := x, y, z,... -- variable
| 0, 1, 2,... -- constant
| (e + e) -- addition
| (e - e) -- subtraction
| (c * e) -- linear multiplication
| (f e1 ... en) -- uninterpreted function
\end{spec}
Predicates
----------
\begin{spec}
p := e -- atom
| e1 == e2 -- equality
| e1 < e2 -- ordering
| (p && p) -- and
| (p || p) -- or
| (not p) -- negation
\end{spec}
Refinement Types
----------------
\begin{spec}
b := Int
| Bool
| ... -- base types
| a, b, c -- type variables
t := {x:b | p} -- refined base
| x:t -> t -- refined function
\end{spec}
Subtyping Judgment
------------------
$$\boxed{\Gamma \vdash t_1 \preceq t_2}$$
Where **environment** $\Gamma$ is a sequence of binders
$$\Gamma \defeq \overline{\bindx{x_i}{t_i}}$$
Hence, we can type:
\begin{code}
{-@ zero' :: Nat @-}
zero' = zero -- zero :: Zero <: Nat
\end{code}
Contracts: Function Types
=========================
{#as}
------
Pre-Conditions
--------------
\begin{code}
safeDiv n d = n `div` d -- crashes if d==0
\end{code}
**Requires** non-zero input divisor `d`
\begin{code}
{-@ type NonZero = {v:Int | v /= 0} @-}
\end{code}
Specify pre-condition as **input type**
\begin{code}
{-@ safeDiv :: n:Int -> d:NonZero -> Int @-}
\end{code}
Precondition: `safeDiv`
-----------------------
Specify pre-condition as **input type**
\begin{spec}
{-@ safeDiv :: n:Int -> d:NonZero -> Int @-}
\end{spec}
Precondition is checked at **call-site**
\begin{code}
{-@ bad :: Nat -> Int @-}
bad n = 10 `safeDiv` n
\end{code}
Precondition: `safeDiv`
-----------------------
Specify pre-condition as **input type**
\begin{spec}
{-@ safeDiv :: n:Int -> d:NonZero -> Int @-}
\end{spec}
Precondition is checked at **call-site**
\begin{code}
{-@ ok :: Nat -> Int @-}
ok n = 10 `safeDiv` (n+1)
\end{code}
Precondition: `safeDiv`
-----------------------
Specify pre-condition as **input type**
\begin{spec}
{-@ safeDiv :: n:Int -> d:NonZero -> Int @-}
\end{spec}
Precondition is checked at **call-site**
\begin{spec}
{-@ ok :: Nat -> Int @-}
ok n = 10 `safeDiv` (n+1)
\end{spec}
**Verifies As**
$$(0 \leq n) \Rightarrow (v = n+1) \Rightarrow (v \not = 0)$$
Post-Conditions
---------------
**Ensures** output is a `Nat` greater than input `x`.
\begin{code}
abs x | 0 <= x = x
| otherwise = 0 - x
\end{code}
Specify post-condition as **output type**
\begin{code}
{-@ abs :: x:Int -> {v:Nat | x <= v} @-}
\end{code}
**Dependent Function Types**
Outputs *refer to* inputs
Postcondition: `abs`
--------------------
Specify post-condition as **output type**
\begin{spec}
{-@ abs :: x:Int -> {v:Nat | x <= v} @-}
abs x | 0 <= x = x
| otherwise = 0 - x
\end{spec}
Postcondition is checked at **return-site**
Postcondition: `abs`
--------------------
Specify post-condition as **output type**
\begin{spec}
{-@ abs :: x:Int -> {v:Nat | x <= v} @-}
abs x | 0 <= x = x
| otherwise = 0 - x
\end{spec}
**Verified As**
$$\begin{array}{rll}
\bindx{x}{\Int},\bindx{\_}{0 \leq x} & \vdash \reftx{v}{v = x} & \subty \reftx{v}{0 \leq v \wedge x \leq v} \\
\bindx{x}{\Int},\bindx{\_}{0 \not \leq x} & \vdash \reftx{v}{v = 0 - x} & \subty \reftx{v}{0 \leq v \wedge x \leq v} \\
\end{array}$$
Postcondition: `abs`
--------------------
Specify post-condition as **output type**
\begin{spec}
{-@ abs :: x:Int -> {v:Nat | x <= v} @-}
abs x | 0 <= x = x
| otherwise = 0 - x
\end{spec}
**Verified As**
$$\begin{array}{rll}
(0 \leq x) & \Rightarrow (v = x) & \Rightarrow (0 \leq v \wedge x \leq v) \\
(0 \not \leq x) & \Rightarrow (v = 0 - x) & \Rightarrow (0 \leq v \wedge x \leq v) \\
\end{array}$$
Recipe Scales Up
----------------
Define type *checker* and get *inference* for free [[PLDI 08]](http://goto.ucsd.edu/~rjhala/papers/liquid_types.pdf)