7: module AbstractRefinements where 8: 9: import Prelude 10: import Language.Haskell.Liquid.Prelude 11: {-@ LIQUID "--no-termination" @-} 12: 13: o, no :: Int 14: maxInt :: Int -> Int -> Int
Problem 1:
How do we specify both increasing and decreasing lists?
Problem 2:
How do we specify iteration-dependence in higher-order functions?
Lets distill it to a simple example...
(First, a few aliases)
67: {-@ type Odd = {v:Int | (v mod 2) = 1} @-} 68: {-@ type Even = {v:Int | (v mod 2) = 0} @-}
maxInt
Compute the larger of two Int
s:
80: maxInt :: Int -> Int -> Int 81: maxInt x y = if y <= x then x else y
maxInt
Has many incomparable refinement types
92: maxInt :: Nat -> Nat -> Nat 93: maxInt :: Even -> Even -> Even 94: maxInt :: Odd -> Odd -> Odd
maxInt
returns one of its two inputs x
and y
If | : | the inputs satisfy a property |
Then | : | the output satisfies that property |
Need to abstract properties over types
Enable quantification over refinements ...
222: {-@ maxInt :: forall <p :: Int -> Prop>. 223: Int<p> -> Int<p> -> Int<p> @-} 224: 225: forall <p :: GHC.Types.Int-> Bool>. {VV : Int<p> | true} -> {VV : Int<p> | true} -> {VV : Int<p> | true}maxInt {VV : Int | ((papp1 p VV))}x {VV : Int | ((papp1 p VV))}y = if {x3 : Int | ((papp1 p x3)) && (x3 == x)}x x1:Int -> x2:Int -> {x2 : Bool | (((Prop x2)) <=> (x1 <= x2))}<= {x3 : Int | ((papp1 p x3)) && (x3 == y)}y then {x3 : Int | ((papp1 p x3)) && (x3 == y)}y else {x3 : Int | ((papp1 p x3)) && (x3 == x)}x
p
that is a property of Int
,
max
takes two Int
s that satisfy p
,
max
returns an Int
that satisfies p
.
Enable quantification over refinements ...
245: {-@ maxInt :: forall <p :: Int -> Prop>. 246: Int<p> -> Int<p> -> Int<p> @-} 247: 248: maxInt x y = if x <= y then y else x
Key idea: Int<p>
is just {v:Int | (p v)}
i.e., Abstract Refinement is an uninterpreted function in SMT logic
263: {-@ maxInt :: forall <p :: Int -> Prop>. 264: Int<p> -> Int<p> -> Int<p> @-} 265: 266: maxInt x y = if x <= y then y else x
Check and Instantiate
maxInt
with args with some refinement,
p
instantiated with same refinement,
288: {-@ o' :: Odd @-} 289: {v : Int | ((v mod 2) == 1)}o' = forall <p :: GHC.Types.Int-> Bool>. {x3 : Int<p> | true} -> {x2 : Int<p> | true} -> {x1 : Int<p> | true}maxInt {x2 : Int | (x2 == (3 : int))}3 {x2 : Int | (x2 == (7 : int))}7 -- p := \v -> Odd v 290: 291: {-@ e' :: Even @-} 292: {v : Int | ((v mod 2) == 0)}e' = forall <p :: GHC.Types.Int-> Bool>. {x3 : Int<p> | true} -> {x2 : Int<p> | true} -> {x1 : Int<p> | true}maxInt {x2 : Int | (x2 == (2 : int))}2 {x2 : Int | (x2 == (8 : int))}8 -- p := \v -> Even v
Or any other property ...
307: {-@ type RGB = {v:_ | (0 <= v && v < 256)} @-} 308: 309: {-@ rgb :: RGB @-} 310: {v : Int | (v < 256) && (0 <= v)}rgb = forall <p :: GHC.Types.Int-> Bool>. {x3 : Int<p> | true} -> {x2 : Int<p> | true} -> {x1 : Int<p> | true}maxInt {x2 : Int | (x2 == (56 : int))}56 {x2 : Int | (x2 == (8 : int))}8 -- p := \v -> 0 <= v < 256