refinement types for haskell
TRANSCRIPT
![Page 1: Refinement types for haskell](https://reader033.vdocuments.net/reader033/viewer/2022042605/58eb8cdc1a28ab82118b473f/html5/thumbnails/1.jpg)
Refinement types for Haskell
![Page 2: Refinement types for haskell](https://reader033.vdocuments.net/reader033/viewer/2022042605/58eb8cdc1a28ab82118b473f/html5/thumbnails/2.jpg)
Martin Ockajak from Zürich
Software Engineer
@martin_ockajak
![Page 3: Refinement types for haskell](https://reader033.vdocuments.net/reader033/viewer/2022042605/58eb8cdc1a28ab82118b473f/html5/thumbnails/3.jpg)
Outline
● Motivation
● Refinement types
● Liquid Haskell
● Practical considerations
![Page 4: Refinement types for haskell](https://reader033.vdocuments.net/reader033/viewer/2022042605/58eb8cdc1a28ab82118b473f/html5/thumbnails/4.jpg)
Motivation
![Page 5: Refinement types for haskell](https://reader033.vdocuments.net/reader033/viewer/2022042605/58eb8cdc1a28ab82118b473f/html5/thumbnails/5.jpg)
Standard type system
● Allows expressing certain properties of programs● Type safety
● Verifiable without running the program● Static type checking
● Integrated with the compilation
● Testing still needed
● Can we do better ?
![Page 6: Refinement types for haskell](https://reader033.vdocuments.net/reader033/viewer/2022042605/58eb8cdc1a28ab82118b473f/html5/thumbnails/6.jpg)
Possible improvements
● Prevent more programming errors● Division by zero
● Missing keys in maps
● Infinite loops
● Express properties of programs in greater detail
● Keep the ability to automatically verify type safety● Verification must be a decidable problem
● No proofs by the programmer required
![Page 7: Refinement types for haskell](https://reader033.vdocuments.net/reader033/viewer/2022042605/58eb8cdc1a28ab82118b473f/html5/thumbnails/7.jpg)
Refinement types
![Page 8: Refinement types for haskell](https://reader033.vdocuments.net/reader033/viewer/2022042605/58eb8cdc1a28ab82118b473f/html5/thumbnails/8.jpg)
Refinement types
● Consist of● Type
● Standard or refinement
● Predicate● Propositional logic
● Can describe valid inputs and outputs of functions● Type safe if the predicate is valid for all inputs
![Page 9: Refinement types for haskell](https://reader033.vdocuments.net/reader033/viewer/2022042605/58eb8cdc1a28ab82118b473f/html5/thumbnails/9.jpg)
Predicate
● Boolean operators● && , || , not , => , <=> , true , false
● Arithmetic operators● + , - , * , / , mod
● Relations● == , /= , < , > , <= , >=
![Page 10: Refinement types for haskell](https://reader033.vdocuments.net/reader033/viewer/2022042605/58eb8cdc1a28ab82118b473f/html5/thumbnails/10.jpg)
Liquid Haskell
![Page 11: Refinement types for haskell](https://reader033.vdocuments.net/reader033/viewer/2022042605/58eb8cdc1a28ab82118b473f/html5/thumbnails/11.jpg)
Liquid Haskell
● Static refinement type verifier● Completely automatic
● Translates refinement types into verification conditions● Satisfiability modulo theories formulas
● Uses an SMT solver to verify those conditions● Without executing the program or enumerating inputs
● Project at University of California - San Diego● http://goto.ucsd.edu/~rjhala/liquid/haskell/blog/about/
![Page 12: Refinement types for haskell](https://reader033.vdocuments.net/reader033/viewer/2022042605/58eb8cdc1a28ab82118b473f/html5/thumbnails/12.jpg)
Defining refinement types● Positive is a subtype of NonZero
● Positive values are a subset of NonZero values
{-@ type NonZero = {v: Int | v /= 0 } @-}{-@ type Positive = {v: Int | v > 0 } @-}{-@ type Odd = {v: Int | v mod 2 == 1 } @-}
{-@ one :: NonZero @-}{-@ one :: Positive @-}{-@ one :: Odd @-}one :: Intone = 1
{-@ odds :: [Odd] @-}odds :: [Int]odds = [1, 3, 7]
![Page 13: Refinement types for haskell](https://reader033.vdocuments.net/reader033/viewer/2022042605/58eb8cdc1a28ab82118b473f/html5/thumbnails/13.jpg)
Refining function results
{-@ two :: {v: Int | v mod 2 == 0 } @-}{-@ one, two :: NonZero @-}two :: Inttwo = 1 + 1
{-@ size :: [a] -> {v: Int | v >= 0 } @-}size :: [a] -> Intsize [] = 0size (x:xs) = 1 + size xs
{-@ positive :: n:Int -> { v: Bool | Prop v <=> n > 0 } @-}positive :: Int -> Boolpositive n = n > 0
![Page 14: Refinement types for haskell](https://reader033.vdocuments.net/reader033/viewer/2022042605/58eb8cdc1a28ab82118b473f/html5/thumbnails/14.jpg)
Refining function arguments
{-@ crash :: {v: String | false } -> a @-}crash :: String -> acrash message = error message
{-@ divide :: Int -> NonZero -> Int @-}divide :: Int -> Int -> Intdivide n 0 = crash "division by zero"divide n d = n `div` d
correctDivide :: IntcorrectDivide = divide 1 1
incorrectDivide :: IntincorrectDivide = divide 1 0
![Page 15: Refinement types for haskell](https://reader033.vdocuments.net/reader033/viewer/2022042605/58eb8cdc1a28ab82118b473f/html5/thumbnails/15.jpg)
Defining predicates
{-@ predicate Positive N = N > 0 @-}{-@ predicate Even N = N mod 2 == 0 @-}{-@ predicate PositiveOdd N = Positive N && not Even N @-}
{-@ type Even = { v: Int | Even v } @-}
{-@ three :: { v: Int | PositiveOdd v || v == 4 } @-}three :: Intthree = 5 - 2
![Page 16: Refinement types for haskell](https://reader033.vdocuments.net/reader033/viewer/2022042605/58eb8cdc1a28ab82118b473f/html5/thumbnails/16.jpg)
Measure functions● Can be used inside refinement type definitions● Single expression for every data constructor
● Propositional logic only
data List a = Emp | (:::) a (List a)
{-@ measure len @-}len :: List a -> Intlen Emp = 0len (x:::xs) = 1 + len xs
{-@ first :: {v: List a | len v > 0 } -> a @-}first Emp = crash "empty list"first (x:::xs) = x
![Page 17: Refinement types for haskell](https://reader033.vdocuments.net/reader033/viewer/2022042605/58eb8cdc1a28ab82118b473f/html5/thumbnails/17.jpg)
Refining data types● Parametrized type alias used to specify list length
data Triple a = Triple (List a)
{-@ type ListN a N = {v: List a | len v == N} @-}
{-@ data Triple a = Triple (ListN a 3) @-}
correctTriple = Triple (1 ::: (2 ::: (3 ::: Emp)))
![Page 18: Refinement types for haskell](https://reader033.vdocuments.net/reader033/viewer/2022042605/58eb8cdc1a28ab82118b473f/html5/thumbnails/18.jpg)
Inline functions and assumptions● Inline functions can be used inside measures● Assumptions allow describing non-verifiable functions
{-@ inline increment2 @-}increment2 :: Int -> Intincrement2 n = n + 2
{-@ measure doubleLen @-}doubleLen :: List a -> IntdoubleLen Emp = 0doubleLen (x:::xs) = increment2 (doubleLen xs)
{-@ assume abs :: (Num a) => a -> {v: a | v > 0 } @-}
![Page 19: Refinement types for haskell](https://reader033.vdocuments.net/reader033/viewer/2022042605/58eb8cdc1a28ab82118b473f/html5/thumbnails/19.jpg)
Recursion
{-@ type NonNegative a = {v: a | v >= 0 } @-}{-@ type Natural a = {v: a | v > 0 } @-}
{-@ fact :: (Integral a) => NonNegative a -> Natural a @-}fact :: (Integral a) => a -> afact 0 = 1fact n = n * fact (n – 1)
correctFact = fact 3
incorrectFact = fact (-1)
![Page 20: Refinement types for haskell](https://reader033.vdocuments.net/reader033/viewer/2022042605/58eb8cdc1a28ab82118b473f/html5/thumbnails/20.jpg)
Practical considerations
![Page 21: Refinement types for haskell](https://reader033.vdocuments.net/reader033/viewer/2022042605/58eb8cdc1a28ab82118b473f/html5/thumbnails/21.jpg)
Practicality – Liquid Haskell
● Compatible with several SMT solvers
● Incremental checking support
● Decent documentation
● Still experimental
![Page 22: Refinement types for haskell](https://reader033.vdocuments.net/reader033/viewer/2022042605/58eb8cdc1a28ab82118b473f/html5/thumbnails/22.jpg)
Thank you :-)