{#simplerefinements} ======================= Simple Refinement Types -----------------------
10: {-@ LIQUID "--no-termination" @-} 11: module SimpleRefinements where 12: import Language.Haskell.Liquid.Prelude 13: import Prelude hiding (abs, max) 14: 15: -- boring haskell type sigs 16: zero :: Int 17: zero' :: Int 18: safeDiv :: Int -> Int -> Int 19: abs :: Int -> Int 20: nats :: L Int 21: evens :: L Int 22: odds :: L Int 23: range :: Int -> Int -> L Int
45: {-@ type EqZero = {v:Int | v = 0} @-}Example ------- Integers equal to `0`
57: {-@ zero :: EqZero @-} 58: {VV : (Int) | (VV == 0)}zero = x1:(Int#) -> {x2 : (Int) | (x2 == (x1 : int))}0
134: type Nat = {v : Int | 0 <= v}
144: {-@ zero' :: Nat @-} 145: {VV : (Int) | (VV >= 0)}zero' = {x3 : (Int) | (x3 == 0) && (x3 == SimpleRefinements.zero)}zero{#universalinvariants} ======================= Types = Universal Invariants ---------------------------- (Notoriously hard with *pure* SMT) Types Yield Universal Invariants ================================ Example: Lists --------------
164: infixr `C`
169: data L a = N | C a (L a)
177: {-@ nats :: L Nat @-} 178: (L {VV : (Int) | (VV >= 0)})nats = {x2 : (Int) | (x2 == (0 : int))}0 {x14 : (Int) | (x14 >= 0) && (x14 >= SimpleRefinements.zero) && (SimpleRefinements.zero <= x14)} -> (L {x14 : (Int) | (x14 >= 0) && (x14 >= SimpleRefinements.zero) && (SimpleRefinements.zero <= x14)}) -> (L {x14 : (Int) | (x14 >= 0) && (x14 >= SimpleRefinements.zero) && (SimpleRefinements.zero <= x14)})`C` {x2 : (Int) | (x2 == (1 : int))}1 {x20 : (Int) | ((x20 mod 2) == 1) && (x20 > 0) && (x20 > SimpleRefinements.zero) && (x20 >= 0) && (SimpleRefinements.zero <= x20)} -> (L {x20 : (Int) | ((x20 mod 2) == 1) && (x20 > 0) && (x20 > SimpleRefinements.zero) && (x20 >= 0) && (SimpleRefinements.zero <= x20)}) -> (L {x20 : (Int) | ((x20 mod 2) == 1) && (x20 > 0) && (x20 > SimpleRefinements.zero) && (x20 >= 0) && (SimpleRefinements.zero <= x20)})`C` {x2 : (Int) | (x2 == (3 : int))}3 {x20 : (Int) | ((x20 mod 2) == 1) && (x20 > 0) && (x20 > SimpleRefinements.zero) && (x20 >= 0) && (SimpleRefinements.zero <= x20)} -> (L {x20 : (Int) | ((x20 mod 2) == 1) && (x20 > 0) && (x20 > SimpleRefinements.zero) && (x20 >= 0) && (SimpleRefinements.zero <= x20)}) -> (L {x20 : (Int) | ((x20 mod 2) == 1) && (x20 > 0) && (x20 > SimpleRefinements.zero) && (x20 >= 0) && (SimpleRefinements.zero <= x20)})`C` (L {x2 : (Int) | false})N
195: {-@ type Even = {v:Int | v mod 2 = 0} @-} 196: {-@ type Odd = {v:Int | v mod 2 /= 0} @-}
203: {-@ evens :: L Even @-} 204: (L {VV : (Int) | ((VV mod 2) == 0)})evens = {x2 : (Int) | (x2 == (0 : int))}0 {x17 : (Int) | ((x17 mod 2) == 0) && (x17 >= 0) && (x17 >= SimpleRefinements.zero) && (SimpleRefinements.zero <= x17)} -> (L {x17 : (Int) | ((x17 mod 2) == 0) && (x17 >= 0) && (x17 >= SimpleRefinements.zero) && (SimpleRefinements.zero <= x17)}) -> (L {x17 : (Int) | ((x17 mod 2) == 0) && (x17 >= 0) && (x17 >= SimpleRefinements.zero) && (SimpleRefinements.zero <= x17)})`C` {x2 : (Int) | (x2 == (2 : int))}2 {x23 : (Int) | ((x23 mod 2) == 0) && (x23 /= 0) && (x23 > 0) && (x23 > SimpleRefinements.zero) && (x23 >= 0) && (SimpleRefinements.zero <= x23)} -> (L {x23 : (Int) | ((x23 mod 2) == 0) && (x23 /= 0) && (x23 > 0) && (x23 > SimpleRefinements.zero) && (x23 >= 0) && (SimpleRefinements.zero <= x23)}) -> (L {x23 : (Int) | ((x23 mod 2) == 0) && (x23 /= 0) && (x23 > 0) && (x23 > SimpleRefinements.zero) && (x23 >= 0) && (SimpleRefinements.zero <= x23)})`C` {x2 : (Int) | (x2 == (4 : int))}4 {x23 : (Int) | ((x23 mod 2) == 0) && (x23 /= 0) && (x23 > 0) && (x23 > SimpleRefinements.zero) && (x23 >= 0) && (SimpleRefinements.zero <= x23)} -> (L {x23 : (Int) | ((x23 mod 2) == 0) && (x23 /= 0) && (x23 > 0) && (x23 > SimpleRefinements.zero) && (x23 >= 0) && (SimpleRefinements.zero <= x23)}) -> (L {x23 : (Int) | ((x23 mod 2) == 0) && (x23 /= 0) && (x23 > 0) && (x23 > SimpleRefinements.zero) && (x23 >= 0) && (SimpleRefinements.zero <= x23)})`C` (L {x2 : (Int) | false})N 205: 206: {-@ odds :: L Odd @-} 207: (L {VV : (Int) | ((VV mod 2) == 1)})odds = {x2 : (Int) | (x2 == (1 : int))}1 {x20 : (Int) | ((x20 mod 2) == 1) && (x20 > 0) && (x20 > SimpleRefinements.zero) && (x20 >= 0) && (SimpleRefinements.zero <= x20)} -> (L {x20 : (Int) | ((x20 mod 2) == 1) && (x20 > 0) && (x20 > SimpleRefinements.zero) && (x20 >= 0) && (SimpleRefinements.zero <= x20)}) -> (L {x20 : (Int) | ((x20 mod 2) == 1) && (x20 > 0) && (x20 > SimpleRefinements.zero) && (x20 >= 0) && (SimpleRefinements.zero <= x20)})`C` {x2 : (Int) | (x2 == (3 : int))}3 {x20 : (Int) | ((x20 mod 2) == 1) && (x20 > 0) && (x20 > SimpleRefinements.zero) && (x20 >= 0) && (SimpleRefinements.zero <= x20)} -> (L {x20 : (Int) | ((x20 mod 2) == 1) && (x20 > 0) && (x20 > SimpleRefinements.zero) && (x20 >= 0) && (SimpleRefinements.zero <= x20)}) -> (L {x20 : (Int) | ((x20 mod 2) == 1) && (x20 > 0) && (x20 > SimpleRefinements.zero) && (x20 >= 0) && (SimpleRefinements.zero <= x20)})`C` {x2 : (Int) | (x2 == (5 : int))}5 {x20 : (Int) | ((x20 mod 2) == 1) && (x20 > 0) && (x20 > SimpleRefinements.zero) && (x20 >= 0) && (SimpleRefinements.zero <= x20)} -> (L {x20 : (Int) | ((x20 mod 2) == 1) && (x20 > 0) && (x20 > SimpleRefinements.zero) && (x20 >= 0) && (SimpleRefinements.zero <= x20)}) -> (L {x20 : (Int) | ((x20 mod 2) == 1) && (x20 > 0) && (x20 > SimpleRefinements.zero) && (x20 >= 0) && (SimpleRefinements.zero <= x20)})`C` (L {x2 : (Int) | false})N
237: {-@ type NonZero = {v:Int | v /= 0} @-}
254: {-@ safeDiv :: Int -> NonZero -> Int @-} 255: (Int) -> {VV : (Int) | (VV /= 0)} -> (Int)safeDiv (Int)x {VV : (Int) | (VV /= 0)}y = {x2 : (Int) | (x2 == x)}x x1:(Int) -> x2:(Int) -> {x6 : (Int) | (((x1 >= 0) && (x2 >= 0)) => (x6 >= 0)) && (((x1 >= 0) && (x2 >= 1)) => (x6 <= x1)) && (x6 == (x1 / x2))}`div` {x3 : (Int) | (x3 == y) && (x3 /= 0)}y
278: {-@ abs :: x:Int -> Nat @-} 279: (Int) -> {VV : (Int) | (VV >= 0)}abs (Int)x 280: | {x2 : (Int) | (x2 == (0 : int))}0 x1:(Int) -> x2:(Int) -> {x2 : (Bool) | (((Prop x2)) <=> (x1 <= x2))}<= {x2 : (Int) | (x2 == x)}x = {x2 : (Int) | (x2 == x)}x 281: | otherwise = {x2 : (Int) | (x2 == (0 : int))}0 x1:(Int) -> x2:(Int) -> {x4 : (Int) | (x4 == (x1 - x2))}- {x2 : (Int) | (x2 == x)}x{#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`
313: {-@ type Btwn I J = {v:_|(I <= v && v < J)} @-}Example: `range` ---------------- `(range i j)` returns `Int`s between `i` and `j`
324: {-@ range :: i:Int -> j:Int -> L (Btwn i j) @-} 325: i:(Int) -> j:(Int) -> (L {v : (Int) | (v < j) && (i <= v)})range (Int)i (Int)j = x1:{x10 : (Int) | (x10 >= i) && (i <= x10)} -> (L {x7 : (Int) | (x7 >= i) && (x7 >= x1) && (x7 < j) && (i <= x7) && (x1 <= x7)})go {x2 : (Int) | (x2 == i)}i 326: where 327: n:{VV : (Int) | (VV >= i) && (i <= VV)} -> (L {VV : (Int) | (VV >= i) && (VV >= n) && (VV < j) && (i <= VV) && (n <= VV)})go {VV : (Int) | (VV >= i) && (i <= VV)}n 328: | {x4 : (Int) | (x4 == n) && (x4 >= i) && (i <= x4)}n x1:(Int) -> x2:(Int) -> {x2 : (Bool) | (((Prop x2)) <=> (x1 < x2))}< {x2 : (Int) | (x2 == j)}j = {x4 : (Int) | (x4 == n) && (x4 >= i) && (i <= x4)}n {x20 : (Int) | (x20 >= i) && (x20 >= n) && (x20 < j) && (i <= x20) && (n <= x20)} -> (L {x20 : (Int) | (x20 >= i) && (x20 >= n) && (x20 < j) && (i <= x20) && (n <= x20)}) -> (L {x20 : (Int) | (x20 >= i) && (x20 >= n) && (x20 < j) && (i <= x20) && (n <= x20)})`C` n:{VV : (Int) | (VV >= i) && (i <= VV)} -> (L {VV : (Int) | (VV >= i) && (VV >= n) && (VV < j) && (i <= VV) && (n <= VV)})go ({x4 : (Int) | (x4 == n) && (x4 >= i) && (i <= x4)}n x1:(Int) -> x2:(Int) -> {x4 : (Int) | (x4 == (x1 + x2))}+ {x2 : (Int) | (x2 == (1 : int))}1) 329: | otherwise = (L {x2 : (Int) | false})N
343: (!) :: L a -> Int -> a 344: (C x _) forall a. (L a) -> (Int) -> a! 0 = {VV : a | (VV == x)}x 345: (C _ xs) ! i = (L a)xs (L a) -> (Int) -> a! ((Int)i x1:(Int) -> x2:(Int) -> {x4 : (Int) | (x4 == (x1 - x2))}- {x2 : (Int) | (x2 == (1 : int))}1) 346: _ ! _ = {x1 : [(Char)] | false} -> {VV : a | false}liquidError {x3 : [(Char)] | ((len x3) >= 0) && ((sumLens x3) >= 0)}"Oops!"