Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Refinement types for haskell

638 views

Published on

Refinement types are an approach for expressing more detailed properties of data types using propositional logic predicates. Liquid Haskell is a static refinement type checker capable of veryfing refinement type safety. We will examine the possibilites this approach opens for increasing development productivity.

Published in: Software
  • Login to see the comments

Refinement types for haskell

  1. 1. Refinement types for Haskell
  2. 2. Martin Ockajak from Zürich Software Engineer @martin_ockajak
  3. 3. Outline ● Motivation ● Refinement types ● Liquid Haskell ● Practical considerations
  4. 4. Motivation
  5. 5. 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 ?
  6. 6. 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
  7. 7. Refinement types
  8. 8. 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
  9. 9. Predicate ● Boolean operators ● && , || , not , => , <=> , true , false ● Arithmetic operators ● + , - , * , / , mod ● Relations ● == , /= , < , > , <= , >=
  10. 10. Liquid Haskell
  11. 11. 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/
  12. 12. 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 :: Int one = 1 {-@ odds :: [Odd] @-} odds :: [Int] odds = [1, 3, 7]
  13. 13. Refining function results {-@ two :: {v: Int | v mod 2 == 0 } @-} {-@ one, two :: NonZero @-} two :: Int two = 1 + 1 {-@ size :: [a] -> {v: Int | v >= 0 } @-} size :: [a] -> Int size [] = 0 size (x:xs) = 1 + size xs {-@ positive :: n:Int -> { v: Bool | Prop v <=> n > 0 } @-} positive :: Int -> Bool positive n = n > 0
  14. 14. Refining function arguments {-@ crash :: {v: String | false } -> a @-} crash :: String -> a crash message = error message {-@ divide :: Int -> NonZero -> Int @-} divide :: Int -> Int -> Int divide n 0 = crash "division by zero" divide n d = n `div` d correctDivide :: Int correctDivide = divide 1 1 incorrectDivide :: Int incorrectDivide = divide 1 0
  15. 15. 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 :: Int three = 5 - 2
  16. 16. 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 -> Int len Emp = 0 len (x:::xs) = 1 + len xs {-@ first :: {v: List a | len v > 0 } -> a @-} first Emp = crash "empty list" first (x:::xs) = x
  17. 17. 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)))
  18. 18. Inline functions and assumptions ● Inline functions can be used inside measures ● Assumptions allow describing non-verifiable functions {-@ inline increment2 @-} increment2 :: Int -> Int increment2 n = n + 2 {-@ measure doubleLen @-} doubleLen :: List a -> Int doubleLen Emp = 0 doubleLen (x:::xs) = increment2 (doubleLen xs) {-@ assume abs :: (Num a) => a -> {v: a | v > 0 } @-}
  19. 19. 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 -> a fact 0 = 1 fact n = n * fact (n – 1) correctFact = fact 3 incorrectFact = fact (-1)
  20. 20. Practical considerations
  21. 21. Practicality – Liquid Haskell ● Compatible with several SMT solvers ● Incremental checking support ● Decent documentation ● Still experimental
  22. 22. Thank you :-)

×