\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
------------------
Example
-------
Integers equal to `0`
\begin{code}
{-@ type EqZero = {v:Int | v = 0} @-}
\end{code}
Example
-------
Integers equal to `0`
\begin{code}
{-@ zero :: EqZero @-}
zero = 0
\end{code}
Refinement types via special comments `{-@ ... @-}`
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}
{#functiontypes}
=================
Contracts = Function Types
--------------------------
Contracts: Function Types
=========================
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 < J)} @-}
\end{code}
Example: `range`
----------------
`(range i j)` returns `Int`s between `i` and `j`
\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}
**Question:** What is the type of `go` ?
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`)
-
**Q:** How to ensure safety?
-
**A:** Precondition: `i` between `0` and list **length**.
Need way to [measure](#measures) *length of a list* ...