--- layout: post title: Refinement Types 101 date: 2013-01-01 16:12 author: Ranjit Jhala published: true comments: true tags: - basic demo: refinements101.hs --- One of the great things about Haskell is its brainy type system that allows one to enforce a variety of invariants at compile time, thereby nipping a large swathe of run-time errors in the bud. Refinement types allow us to use modern logic solvers (*aka* SAT and SMT engines) to dramatically extend the scope of invariants that can be statically verified. What is a Refinement Type? -------------------------- In a nutshell,

Refinement Types = Types + Logical Predicates

That is, refinement types allow us to decorate types with *logical predicates* (think *boolean-valued* Haskell expressions) which constrain the set of values described by the type, and hence allow us to specify sophisticated invariants of the underlying values. Say what? (Btw, *click the title* to demo LiquidHaskell on the code in this article)
42: module Intro where
43: 
44: import Language.Haskell.Liquid.Prelude  (liquidAssert)
Let us jump right in with a simple example, the number `0 :: Int`. As far as Haskell is concerned, the number is simply an `Int` (lets not worry about things like `Num` for the moment). So are `2`, `7`, and `904`. With refinements we can dress up these values so that they stand apart. For example, consider the binder
54: zero' :: Int
55: {VV : (GHC.Types.Int) | (0 <= VV)}zero' = x:(GHC.Prim.Int#) -> {VV : (GHC.Types.Int) | (VV = (x  :  int))}0
We can ascribe to the variable `zero'` the refinement type
61: {-@ zero' :: {v: Int | 0 <= v} @-}
which is simply the basic type `Int` dressed up with a predicate. The binder `v` is called the *value variable*, and so the above denotes the set of `Int` values which are greater than `0`. Of course, we can attach other predicates to the above value, for example **Note:** We will use `@`-marked comments to write refinement type annotations the Haskell source file, making these types, quite literally, machine-checked comments!
75: {-@ zero'' :: {v: Int | (0 <= v && v < 100) } @-}
76: zero'' :: Int
77: {VV : (GHC.Types.Int) | (VV < 100),(0 <= VV)}zero'' = x:(GHC.Prim.Int#) -> {VV : (GHC.Types.Int) | (VV = (x  :  int))}0
which states that the number is in the range `0` to `100`, or
83: {-@ zero''' :: {v: Int | ((v mod 2) = 0) } @-}
84: zero''' :: Int
85: {VV : (GHC.Types.Int) | ((VV mod 2) = 0)}zero''' = x:(GHC.Prim.Int#) -> {VV : (GHC.Types.Int) | (VV = (x  :  int))}0
where `mod` is the *modulus* operator in the refinement logic. Thus, the type above states that zero is an *even* number. We can also use a singleton type that precisely describes the constant
94: {-@ zero'''' :: {v: Int | v = 0 } @-}
95: zero'''' :: Int
96: {VV : (GHC.Types.Int) | (VV = 0)}zero'''' = x:(GHC.Prim.Int#) -> {VV : (GHC.Types.Int) | (VV = (x  :  int))}0
(Aside: we use a different names `zero'`, `zero''` etc. for a silly technical reason -- LiquidHaskell requires that we ascribe a single refinement type to a top-level name.) Finally, we could write a single type that captures all the properties above:
106: {-@ zero :: {v: Int | ((0 <= v) && ((v mod 2) = 0) && (v < 100)) } @-}
107: zero     :: Int
108: {VV : (GHC.Types.Int) | ((VV mod 2) = 0),(VV < 100),(0 <= VV)}zero     =  x:(GHC.Prim.Int#) -> {VV : (GHC.Types.Int) | (VV = (x  :  int))}0
The key points are: 1. A refinement type is just a type *decorated* with logical predicates. 2. A value can have *different* refinement types that describe different properties. 3. If we *erase* the green bits (i.e. the logical predicates) we get back *exactly* the usual Haskell types that we know and love. 4. A vanilla Haskell type, say `Int` has the trivial refinement `true` i.e. is really `{v: Int | true}`. We have built a refinement type-based verifier called LiquidHaskell. Lets see how we can use refinement types to specify and verify interesting program invariants in LiquidHaskell. Writing Safety Specifications ----------------------------- We can use refinement types to write various kinds of more interesting safety specifications. First, we can write a wrapper around the usual `error` function
133: {-@ error' :: {v: String | false } -> a  @-}
134: error'     :: String -> a
135: {VV : [(GHC.Types.Char)] | false} -> aerror'     = [(GHC.Types.Char)] -> aerror
The interesting thing about the type signature for `error'` is that the input type has the refinement `false`. That is, the function must only be called with `String`s that satisfy the predicate `false`. Of course, there are *no* such values. Thus, a program containing the above function typechecks *exactly* when LiquidHaskell can prove that the function `error'` is *never called*. Next, we can use refinements to encode arbitrary programmer-specified **assertions** by defining a function
149: {-@ lAssert     :: {v:Bool | (Prop v)} -> a -> a  @-}
150: lAssert         :: Bool -> a -> a 
151: {VV : (GHC.Types.Bool) | (? Prop([VV]))} -> a -> alAssert True  ax = {VV : a | (VV = x)}x
152: lAssert False _ = {VV : [(GHC.Types.Char)] | false} -> {VV : a | false}error' {VV : [(GHC.Types.Char)] | (len([VV]) >= 0)}"lAssert failure" 
In the refinement, `(Prop v)` denotes the Haskell `Bool` value `v` interpreted as a logical predicate. In other words, the input type for this function specifies that the function must *only* be called with the value `True`. Refining Function Types : Preconditions --------------------------------------- Lets use the above to write a *divide* function that *only accepts* non-zero denominators.
168: divide     :: Int -> Int -> Int
169: (GHC.Types.Int)
-> {VV : (GHC.Types.Int) | (VV != 0)} -> (GHC.Types.Int)divide (GHC.Types.Int)n 0 = {VV : [(GHC.Types.Char)] | false} -> {VV : (GHC.Types.Int) | false}error' {VV : [(GHC.Types.Char)] | (len([VV]) >= 0)}"divide by zero"
170: divide n d = {VV : (GHC.Types.Int) | (VV = n)}n x:(GHC.Types.Int)
-> y:(GHC.Types.Int) -> {VV : (GHC.Types.Int) | (VV = (x / y))}`div` {VV : (GHC.Types.Int) | (VV != 0)}d
We can specify that the non-zero denominator *precondition* with a suitable refinement on the *input* component of the function's type
177: {-@ divide :: Int -> {v: Int | v != 0 } -> Int @-}
How *does* LiquidHaskell verify the above function? The key step is that LiquidHaskell deduces that the expression `"divide by zero"` is not merely of type `String`, but in fact has the the refined type `{v:String | false}` *in the context* in which the call to `error'` occurs. LiquidHaskell arrives at this conclusion by using the fact that in the first equation for `divide` the *denominator* parameter is in fact `0 :: {v: Int | v = 0}` which *contradicts* the precondition (i.e. input) type. In other words, LiquidHaskell deduces by contradiction, that the first equation is **dead code** and hence `error'` will not be called at run-time. If you are paranoid, you can put in an explicit assertion
199: divide'     :: Int -> Int -> Int
200: {VV : (GHC.Types.Int) | false}
-> {VV : (GHC.Types.Int) | false} -> {VV : (GHC.Types.Int) | false}divide' {VV : (GHC.Types.Int) | false}n 0 = {VV : [(GHC.Types.Char)] | false} -> {VV : (GHC.Types.Int) | false}error' {VV : [(GHC.Types.Char)] | (len([VV]) >= 0)}"divide by zero"
201: divide' n d = {VV : (GHC.Types.Bool) | (? Prop([VV]))}
-> {VV : (GHC.Types.Int) | false} -> {VV : (GHC.Types.Int) | false}lAssert ({VV : (GHC.Types.Int) | false}d x:{VV : (GHC.Types.Int) | false}
-> y:{VV : (GHC.Types.Int) | false}
-> {VV : (GHC.Types.Bool) | ((? Prop([VV])) <=> (x != y))}/= {VV : (GHC.Types.Int) | (VV = (0  :  int))}0) ({VV : (GHC.Types.Int) | false} -> {VV : (GHC.Types.Int) | false})
-> {VV : (GHC.Types.Int) | false} -> {VV : (GHC.Types.Int) | false}$ {VV : (GHC.Types.Int) | false}n x:(GHC.Types.Int)
-> y:(GHC.Types.Int) -> {VV : (GHC.Types.Int) | (VV = (x / y))}`div` {VV : (GHC.Types.Int) | false}d
and LiquidHaskell will verify the assertion (by verifying the call to `lAssert`) for you. Refining Function Types : Postconditions ---------------------------------------- Next, lets see how we can use refinements to describe the *outputs* of a function. Consider the following simple *absolute value* function
214: abz               :: Int -> Int
215: (GHC.Types.Int) -> {VV : (GHC.Types.Int) | (0 <= VV)}abz (GHC.Types.Int)n | {VV : (GHC.Types.Int) | (VV = (0  :  int))}0 x:(GHC.Types.Int)
-> y:(GHC.Types.Int)
-> {VV : (GHC.Types.Bool) | ((? Prop([VV])) <=> (x < y))}< {VV : (GHC.Types.Int) | (VV = n)}n     = {VV : (GHC.Types.Int) | (VV = n)}n
216:       | otherwise = {VV : (GHC.Types.Int) | (VV = (0  :  int))}0 x:(GHC.Types.Int)
-> y:(GHC.Types.Int) -> {VV : (GHC.Types.Int) | (VV = (x - y))}- {VV : (GHC.Types.Int) | (VV = n)}n
We can use a refinement on the output type to specify that the function returns non-negative values
223: {-@ abz :: Int -> {v: Int | 0 <= v } @-}
LiquidHaskell *verifies* that `abz` indeed enjoys the above type by deducing that `n` is trivially non-negative when `0 < n` and that in the `otherwise` case, i.e. when `not (0 < n)` the value `0 - n` is indeed non-negative (lets not worry about underflows for the moment.) LiquidHaskell is able to automatically make these arithmetic deductions by using an [SMT solver](http://rise4fun.com/Z3/) which has decision built-in procedures for arithmetic, to reason about the logical refinements. Putting It All Together ----------------------- Lets wrap up this introduction with a simple `truncate` function that connects all the dots.
244: {-@ truncate :: Int -> Int -> Int @-}
245: (GHC.Types.Int) -> (GHC.Types.Int) -> (GHC.Types.Int)truncate (GHC.Types.Int)i (GHC.Types.Int)max  
246:   | {VV : (GHC.Types.Int) | (VV = i'),(0 <= VV)}i' x:{VV : (GHC.Types.Int) | (VV >= 0),(VV >= zero''''),(0 <= VV)}
-> y:{VV : (GHC.Types.Int) | (VV >= 0),(VV >= zero''''),(0 <= VV)}
-> {VV : (GHC.Types.Bool) | ((? Prop([VV])) <=> (x <= y))}<= {VV : (GHC.Types.Int) | (VV = max'),(0 <= VV)}max' = {VV : (GHC.Types.Int) | (VV = i)}i
247:   | otherwise  = {VV : (GHC.Types.Int) | (VV = max'),(0 <= VV)}max' x:(GHC.Types.Int)
-> y:(GHC.Types.Int)
-> {VV : (GHC.Types.Int) | (&& [(x >= 0); (y >= 0)] => (VV >= 0))}* ({VV : (GHC.Types.Int) | (VV = i)}i (GHC.Types.Int)
-> {VV : (GHC.Types.Int) | (VV != 0)} -> (GHC.Types.Int)`divide` {VV : (GHC.Types.Int) | (VV = i'),(0 <= VV)}i')
248:     where {VV : (GHC.Types.Int) | (0 <= VV)}i'   = (GHC.Types.Int) -> {VV : (GHC.Types.Int) | (0 <= VV)}abz {VV : (GHC.Types.Int) | (VV = i)}i
249:           {VV : (GHC.Types.Int) | (0 <= VV)}max' = (GHC.Types.Int) -> {VV : (GHC.Types.Int) | (0 <= VV)}abz {VV : (GHC.Types.Int) | (VV = max)}max 
`truncate i n` simply returns `i` if its absolute value is less the upper bound `max`, and otherwise *truncates* the value at the maximum. LiquidHaskell verifies that the use of `divide` is safe by inferring that at the call site 1. `i' > max'` from the branch condition. 2. `0 <= i'` from the `abz` postcondition (hover mouse over `i'`). 3. `0 <= max'` from the `abz` postcondition (hover mouse over `max'`). From the above, LiquidHaskell infers that `i' != 0`. That is, at the call site `i' :: {v: Int | v != 0}`, thereby satisfying the precondition for `divide` and verifying that the program has no pesky divide-by-zero errors. Again, if you *really* want to make sure, put in an assertion
268: {-@ truncate' :: Int -> Int -> Int @-}
269: (GHC.Types.Int) -> (GHC.Types.Int) -> (GHC.Types.Int)truncate' (GHC.Types.Int)i (GHC.Types.Int)max  
270:   | {VV : (GHC.Types.Int) | (VV = i'),(0 <= VV)}i' x:{VV : (GHC.Types.Int) | (VV >= 0),(VV >= zero''''),(0 <= VV)}
-> y:{VV : (GHC.Types.Int) | (VV >= 0),(VV >= zero''''),(0 <= VV)}
-> {VV : (GHC.Types.Bool) | ((? Prop([VV])) <=> (x <= y))}<= {VV : (GHC.Types.Int) | (VV = max'),(0 <= VV)}max' = {VV : (GHC.Types.Int) | (VV = i)}i
271:   | otherwise  = {VV : (GHC.Types.Bool) | (? Prop([VV]))}
-> (GHC.Types.Int) -> (GHC.Types.Int)lAssert ({VV : (GHC.Types.Int) | (VV = i'),(0 <= VV)}i' x:{VV : (GHC.Types.Int) | (VV >= 0),
                          (VV >= zero''''),
                          (0 <= VV),
                          (VV <= i')}
-> y:{VV : (GHC.Types.Int) | (VV >= 0),
                             (VV >= zero''''),
                             (0 <= VV),
                             (VV <= i')}
-> {VV : (GHC.Types.Bool) | ((? Prop([VV])) <=> (x != y))}/= {VV : (GHC.Types.Int) | (VV = (0  :  int))}0) ((GHC.Types.Int) -> (GHC.Types.Int))
-> (GHC.Types.Int) -> (GHC.Types.Int)$ {VV : (GHC.Types.Int) | (VV = max'),(0 <= VV)}max' x:(GHC.Types.Int)
-> y:(GHC.Types.Int)
-> {VV : (GHC.Types.Int) | (&& [(x >= 0); (y >= 0)] => (VV >= 0))}* ({VV : (GHC.Types.Int) | (VV = i)}i (GHC.Types.Int)
-> {VV : (GHC.Types.Int) | (VV != 0)} -> (GHC.Types.Int)`divide` {VV : (GHC.Types.Int) | (VV = i'),(0 <= VV)}i')
272:     where {VV : (GHC.Types.Int) | (0 <= VV)}i'   = (GHC.Types.Int) -> {VV : (GHC.Types.Int) | (0 <= VV)}abz {VV : (GHC.Types.Int) | (VV = i)}i
273:           {VV : (GHC.Types.Int) | (0 <= VV)}max' = (GHC.Types.Int) -> {VV : (GHC.Types.Int) | (0 <= VV)}abz {VV : (GHC.Types.Int) | (VV = max)}max 
and *lo!* LiquidHaskell will verify it for you. Modular Verification -------------------- Incidentally, note the `import` statement at the top. Rather than rolling our own `lAssert` we can import and use a pre-defined version `liquidAssert` defined in an external [module](https://github.com/ucsd-progsys/liquidhaskell/blob/master/include/Language/Haskell/Liquid/Prelude.hs)
286: {-@ truncate'' :: Int -> Int -> Int @-}
287: (GHC.Types.Int) -> (GHC.Types.Int) -> (GHC.Types.Int)truncate'' (GHC.Types.Int)i (GHC.Types.Int)max  
288:   | {VV : (GHC.Types.Int) | (VV = i'),(0 <= VV)}i' x:{VV : (GHC.Types.Int) | (VV >= 0),(VV >= zero''''),(0 <= VV)}
-> y:{VV : (GHC.Types.Int) | (VV >= 0),(VV >= zero''''),(0 <= VV)}
-> {VV : (GHC.Types.Bool) | ((? Prop([VV])) <=> (x <= y))}<= {VV : (GHC.Types.Int) | (VV = max'),(0 <= VV)}max' = {VV : (GHC.Types.Int) | (VV = i)}i
289:   | otherwise  = {VV : (GHC.Types.Bool) | (? Prop([VV]))}
-> (GHC.Types.Int) -> (GHC.Types.Int)liquidAssert ({VV : (GHC.Types.Int) | (VV = i'),(0 <= VV)}i' x:{VV : (GHC.Types.Int) | (VV >= 0),
                          (VV >= zero''''),
                          (0 <= VV),
                          (VV <= i')}
-> y:{VV : (GHC.Types.Int) | (VV >= 0),
                             (VV >= zero''''),
                             (0 <= VV),
                             (VV <= i')}
-> {VV : (GHC.Types.Bool) | ((? Prop([VV])) <=> (x != y))}/= {VV : (GHC.Types.Int) | (VV = (0  :  int))}0) ((GHC.Types.Int) -> (GHC.Types.Int))
-> (GHC.Types.Int) -> (GHC.Types.Int)$ {VV : (GHC.Types.Int) | (VV = max'),(0 <= VV)}max' x:(GHC.Types.Int)
-> y:(GHC.Types.Int)
-> {VV : (GHC.Types.Int) | (&& [(x >= 0); (y >= 0)] => (VV >= 0))}* ({VV : (GHC.Types.Int) | (VV = i)}i (GHC.Types.Int)
-> {VV : (GHC.Types.Int) | (VV != 0)} -> (GHC.Types.Int)`divide` {VV : (GHC.Types.Int) | (VV = i'),(0 <= VV)}i')
290:     where {VV : (GHC.Types.Int) | (0 <= VV)}i'   = (GHC.Types.Int) -> {VV : (GHC.Types.Int) | (0 <= VV)}abz {VV : (GHC.Types.Int) | (VV = i)}i
291:           {VV : (GHC.Types.Int) | (0 <= VV)}max' = (GHC.Types.Int) -> {VV : (GHC.Types.Int) | (0 <= VV)}abz {VV : (GHC.Types.Int) | (VV = max)}max 
In fact, LiquidHaskell comes equipped with suitable refinements for standard functions and it is easy to add refinements as we shall demonstrate in subsequent articles. Conclusion ---------- This concludes our quick introduction to Refinement Types and LiquidHaskell. Hopefully you have some sense of how to 1. **Specify** fine-grained properties of values by decorating their types with logical predicates. 2. **Encode** assertions, preconditions, and postconditions with suitable function types. 3. **Verify** semantic properties of code by using automatic logic engines (SMT solvers) to track and establish the key relationships between program values.