\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
nats :: L Int
evens :: L Int
odds :: L Int
range :: Int -> Int -> L Int
\end{code}
Simple Refinement Types
=======================
Types + Predicates
------------------
Ex: `Int`egers equal to `0`
---------------------------
\begin{code}
{-@ type EqZero = {v:Int | v = 0} @-}
{-@ zero :: EqZero @-}
zero = 0
\end{code}
Refinement types via special comments `{-@ ... @-}`
Demo
Refinements Are Predicates
==========================
From A Decidable Logic
----------------------
1. Expressions
2. Predicates
Expressions
-----------
\begin{code}
e := x, y, z,... -- variable
| 0, 1, 2,... -- constant
| (e + e) -- addition
| (e - e) -- subtraction
| (c * e) -- linear multiplication
| (v e1 e2 ... en) -- uninterpreted function
\end{code}
Predicates
----------
\begin{code}
p := e -- atom
| e1 == e2 -- equality
| e1 < e2 -- ordering
| (p && p) -- and
| (p || p) -- or
| (not p) -- negation
\end{code}
Subtyping is Implication
------------------------
[PVS' Predicate Subtyping](http://pvs.csl.sri.com/papers/subtypes98/tse98.pdf)
Subtyping is Implication
------------------------
Example: Even/Odd Lists
-----------------------
\begin{code}
{-@ type Even = {v:Int | v mod 2 = 0} @-}
{-@ type Odd = {v:Int | v mod 2 /= 0} @-}
\end{code}
\begin{code}
{-@ evens :: L Even @-}
evens = 0 `C` 2 `C` 4 `C` N
{-@ odds :: L Odd @-}
odds = 1 `C` 3 `C` 5 `C` N
\end{code}
Contracts: Function Types
=========================
{#as}
------
Example: `safeDiv`
------------------
**Precondition** divisor is *non-zero*.
\begin{code}
{-@ type NonZero = {v:Int | v /= 0} @-}
\end{code}
Example: `safeDiv`
------------------
+ **Pre-condition** divisor is *non-zero*.
+ **Input type** specifies *pre-condition*
\begin{code}
{-@ safeDiv :: Int -> NonZero -> Int @-}
safeDiv x y = x `div` y
\end{code}
Example: `abs`
--------------
+ **Postcondition** result is non-negative
+ **Output type** specifies *post-condition*
\begin{code}
{-@ abs :: x:Int -> Nat @-}
abs x
| 0 <= x = x
| otherwise = 0 - x
\end{code}
{#dependentfunctions}
======================
Dependent Function Types
------------------------
Outputs **refer to** inputs
**Relational** invariants
Dependent Function Types
========================
Example: `range`
----------------
`(range i j)` returns `Int`s **between** `i` and `j`
Example: `range`
----------------
`(range i j)` returns `Int`s **between** `i` and `j`
\begin{code}
{-@ type Btwn I J = {v:_ | (I<=v && v
\begin{code}
{-@ range :: i:Int -> j:Int -> L (Btwn i j) @-}
range i j = go i
where
go n | n < j = n `C` go (n + 1)
| otherwise = N
\end{code}
**Note:** Type of `go` is automatically inferred
Example: Indexing Into List
---------------------------
\begin{code}
(!) :: L a -> Int -> a
(C x _) ! 0 = x
(C _ xs) ! i = xs ! (i - 1)
_ ! _ = liquidError "Oops!"
\end{code}
(Mouseover to view type of `liquidError`)
To ensure safety, *require* `i` between `0` and list **length**
Need way to **measure** the length of a list [[continue...]](02_Measures.lhs.slides.html)