Sound Haskell Dana N. Xu University of Cambridge Joint work with Simon Peyton Jones Microsoft Research Cambridge Koen Claessen Chalmers University of Technology.

Slides:



Advertisements
Similar presentations
Automated Theorem Proving Lecture 1. Program verification is undecidable! Given program P and specification S, does P satisfy S?
Advertisements

Static Contract Checking for Haskell Dana N. Xu University of Cambridge Ph.D. Supervisor: Simon Peyton Jones Microsoft Research Cambridge.
Chapter Three: Closure Properties for Regular Languages
CSE341: Programming Languages Lecture 2 Functions, Pairs, Lists Dan Grossman Winter 2013.
Extended Static Checking for Haskell (ESC/Haskell) Dana N. Xu University of Cambridge advised by Simon Peyton Jones Microsoft Research, Cambridge.
TOWARDS A FINITE MODEL THEORY FOR HIGHER-ORDER PROGRAM VERIFICATION Dimitrios Vytiniotis, Koen Claessen, Simon Peyton Jones, Dan Rosén WG2.8 – Annapolis,
Patterns in ML functions. Formal vs. actual parameters Here's a function definition (in C): –int add (int x, int y) { return x + y; } –x and y are the.
0 PROGRAMMING IN HASKELL Chapter 7 - Higher-Order Functions.
0 PROGRAMMING IN HASKELL Chapter 4 - Defining Functions.
0 PROGRAMMING IN HASKELL Chapter 6 - Recursive Functions Most of this should be review for you.
0 PROGRAMMING IN HASKELL Chapter 6 - Recursive Functions.
Sparkle A theorem prover for the functional language Clean Maarten de Mol University of Nijmegen February 2002.
Type Inference: CIS Seminar, 11/3/2009 Type inference: Inside the Type Checker. A presentation by: Daniel Tuck.
Simon Peyton Jones Microsoft Research Joint work with Dana Xu, University of Cambridge Dec 2007.
Comp 205: Comparative Programming Languages Functional Programming Languages: More Lists Recursive definitions List comprehensions Lecture notes, exercises,
Software Engineering Prof. Dr. Bertrand Meyer March 2007 – June 2007 Chair of Software Engineering Static program checking and verification Slides: Based.
1 Static Contract Checking for Haskell Dana N. Xu INRIA France Work done at University of Cambridge Joint work with Simon Peyton Jones Microsoft Research.
0 REVIEW OF HASKELL A lightening tour in 45 minutes.
0 PROGRAMMING IN HASKELL Chapter 7 - Defining Functions, List Comprehensions.
1-Nov-15 Haskell II Functions and patterns. Data Types Int + - * / ^ even odd Float + - * / ^ sin cos pi truncate Char ord chr isSpace isUpper … Bool.
0 PROGRAMMING IN HASKELL Chapter 9 - Higher-Order Functions, Functional Parsers.
1 Functional Programming Lecture 6 - Algebraic Data Types.
A Second Look At ML 1. Outline Patterns Local variable definitions A sorting example 2.
Overview of the Haskell 98 Programming Language
0 Odds and Ends in Haskell: Folding, I/O, and Functors Adapted from material by Miran Lipovaca.
CS5205Haskell1 CS5205: Foundations in Programming Languages Overview Lecturer : Chin Wei Ngan Office : S “Language.
Lee CSCE 314 TAMU 1 CSCE 314 Programming Languages Haskell: Higher-order Functions Dr. Hyunyoung Lee.
1 CS 457/557: Functional Languages Lists and Algebraic Datatypes Mark P Jones Portland State University.
Advanced Formal Methods Lecture 3: Simply Typed Lambda calculus Mads Dam KTH/CSC Course 2D1453, Some material from B. Pierce: TAPL + some from.
1 Static Contract Checking for Haskell Dana N. Xu University of Cambridge Joint work with Simon Peyton Jones Microsoft Research Cambridge Koen Claessen.
0 PROGRAMMING IN HASKELL Chapter 4 - Defining Functions.
Lee CSCE 314 TAMU 1 CSCE 314 Programming Languages Haskell: More on Functions and List Comprehensions Dr. Hyunyoung Lee.
Chapter SevenModern Programming Languages1 A Second Look At ML.
1 Static Contract Checking for Haskell Dana N. Xu University of Cambridge Joint work with Simon Peyton Jones Microsoft Research Cambridge Koen Claessen.
Static Techniques for V&V. Hierarchy of V&V techniques Static Analysis V&V Dynamic Techniques Model Checking Simulation Symbolic Execution Testing Informal.
Types and Programming Languages Lecture 14 Simon Gay Department of Computing Science University of Glasgow 2006/07.
0 PROGRAMMING IN HASKELL Based on lecture notes by Graham Hutton The book “Learn You a Haskell for Great Good” (and a few other sources) Odds and Ends,
1 Testing in Haskell: using HUnit Notes, thanks to Mark P Jones Portland State University.
Haskell Chapter 4. Recursion  Like other languages  Base case  Recursive call  Author programs a number of built-in functions as examples.
Functional Programming Lecture 3 - Lists Muffy Calder.
Haskell Chapter 5, Part II. Topics  Review/More Higher Order Functions  Lambda functions  Folds.
An introduction to functional programming using Haskell CENG242 –Recitation 1.
6-Jul-16 Haskell II Functions and patterns. Data Types Int + - * / ^ even odd Float + - * / ^ sin cos pi truncate Char ord chr isSpace isUpper … Bool.
GADTs meet their match George Karachalias(Ghent University, Belgium) Tom Schrijvers (KU Leuven, Belgium) Dimitrios Vytiniotis(Microsoft Research Cambridge,
Functional Programming
Conditional Expressions
Programming Languages
Types CSCE 314 Spring 2016.
CSE341: Programming Languages Lecture 2 Functions, Pairs, Lists
A lightening tour in 45 minutes
PROGRAMMING IN HASKELL
PROGRAMMING IN HASKELL
PROGRAMMING IN HASKELL
PROGRAMMING IN HASKELL
PROGRAMMING IN HASKELL
PROGRAMMING IN HASKELL
Programming Languages
Extended Static Checking for Haskell (ESC/Haskell)
PROGRAMMING IN HASKELL
CSE341: Programming Languages Lecture 2 Functions, Pairs, Lists
CSE341: Programming Languages Lecture 2 Functions, Pairs, Lists
CSE341: Programming Languages Lecture 2 Functions, Pairs, Lists
CSE341: Programming Languages Lecture 2 Functions, Pairs, Lists
CSCE 314: Programming Languages Dr. Dylan Shell
PROGRAMMING IN HASKELL
PROGRAMMING IN HASKELL
CSE341: Programming Languages Lecture 2 Functions, Pairs, Lists
CSE341: Programming Languages Lecture 2 Functions, Pairs, Lists
Static Contract Checking for Haskell
Presentation transcript:

Sound Haskell Dana N. Xu University of Cambridge Joint work with Simon Peyton Jones Microsoft Research Cambridge Koen Claessen Chalmers University of Technology

Module UserPgm where f :: [Int]->Int f xs = head xs `max` 0 : … f [] … Program Errors Give Headache! Glasgow Haskell Compiler (GHC) gives at run-time Exception: Prelude.head: empty list Module Prelude where head :: [a] -> a head (x:xs) = x head [] = error “empty list”

Types >> > > > > Contracts >> > > > > head (x:xs) = x head :: [Int] -> Int …(head 1)… head :: {x | not (null xs)} -> {r | True} …(head [])… Bug! Contract (original Haskell boolean expression) Type not :: Bool -> Bool not True = False not False = True null :: [a] -> Bool null [] = True null (x:xs) = False

Preconditions head :: {xs | not (null xs)} -> {r | True} head (x:xs’) = x f xs = head xs `max` 0 Warning: f [] calls head which may fail head’s precondition! f_ok xs = if null xs then 0 else head xs `max` 0 No more warnings from compiler!

Expressiveness of the Specification Language data T = T1 Bool | T2 Int | T3 T T sumT :: T -> Int sumT :: {x | noT1 x} -> {r | True} sumT (T2 a) = a sumT (T3 t1 t2) = sumT t1 + sumT t2 noT1 :: T -> Bool noT1 (T1 _) = False noT1 (T2 _) = True noT1 (T3 t1 t2) = noT1 t1 && noT1 t2

Expressiveness of the Specification Language sumT :: T -> Int sumT :: {x | noT1 x} -> {r | True} sumT (T2 a) = a sumT (T3 t1 t2) = sumT t1 + sumT t2 rmT1 :: T -> T rmT1 :: {x | True} -> {r | noT1 r} rmT1 (T1 a) = if a then T2 1 else T2 0 rmT1 (T2 a) = T2 a rmT1 (T3 t1 t2) = T3 (rmT1 t1) (rmT1 t2) For all crash-free t::T, sumT (rmT1 t) will not crash.

Functions without Annotations data T = T1 Bool | T2 Int | T3 T T noT1 :: T -> Bool noT1 (T1 _) = False noT1 (T2 _) = True noT1 (T3 t1 t2) = noT1 t1 && noT1 t2 (&&) True x = x (&&) False x = False No abstraction is more compact than the function definition itself!

Higher Order Functions all :: (a -> Bool) -> [a] -> Bool all f [] = True all f (x:xs) = f x && all f xs filter :: (a -> Bool) -> [a] -> [a] filter :: {p | True} -> {xs | True} -> {r | all p r} filter p [] = [] filter p (x:xs’) = case (p x) of True -> x : filter p xs’ False -> filter p xs’

Contracts for higher-order function’s parameter f1 :: (Int -> Int) -> Int f1 :: ({x | True} -> {y | y >= 0}) -> {r | r >= 0} f1 g = (g 1) - 1 f2:: {r | True} f2 = f1 (\x -> x – 1) Error: f1’s postcondition fails because (g 1) >= 0 does not imply (g 1) – 1 >= 0 Error: f2 calls f1 which fails f1’s precondition

Laziness fst (a,b) = a Option 1 (  ) fst :: {x | True} -> {r | True} Option 2 ( ) fst :: ({x | True}, Any) -> {r | True} …fst (5, error “f”)… fstN :: (Int, Int) -> Int fstN :: ({x | True}, Any) -> {r | True} fstN (a, b) n = if n > 0 then fstN (a+1, b) (n-1) else a g2 = fstN (5, error “fstN”) 100 Every expression satisfies Any

Various Examples zip :: [a] -> [b] -> [(a,b)] zip :: {xs | True} -> {ys | sameLen xs ys} -> {rs | sameLen rs xs } sameLen [] [] = True sameLen (x:xs) (y:ys) = sameLen xs ys sameLen _ _ = False f91 :: Int -> Int f91 :: { n {r | r == 91 } f91 n = case (n <= 100) of True -> f91 (f91 (n + 11)) False -> n – 10

Sorting sorted [] = True sorted (x:[]) = True sorted (x:y:xs) = x <= y && sorted (y : xs) insert :: {i | True} -> {xs | sorted xs} -> {r | sorted r} merge :: [Int] -> [Int] -> [Int] merge :: {xs | sorted xs} -> {ys | sorted ys} -> {r | sorted r} bubbleHelper :: [Int] -> ([Int], Bool) bubbleHelper :: {xs | True} -> {r | not (snd r) ==> sorted (fst r)} Insertsort, mergesort, bubblesort :: {xs | True} -> {r | sorted r} (==>) True x = x (==>) False x = True

Contract Synonym type Ok = {x | True} type NonNull = {x | not (null x)} head :: [Int] -> Int head :: NonNull -> Ok head (x:xs) = x {-# type Ok = {x | True} -#} {-# type NonNull = {x | not (null x)} #-} {-# contract head :: NonNull -> Ok #-} Actual Syntax

What we can’t do g1, g2 :: Ok -> Ok g1 x = case (prime x > square x) of True -> x False -> error “urk” g2 xs ys = case (rev (xs ++ ys) == rev ys ++ rev xs) of True -> xs False -> error “urk” Hence, three possible outcomes: (1) Definitely Safe (no crash, but may loop) (2) Definite Bug (definitely crashes) (3) Possible Bug Crash!

Language Syntax following Haskell’s lazy semantics

Two special constructors  BAD is an expression that crashes. error :: String -> a error s = BAD head (x:xs) = x head [] = BAD  UNR (short for “unreachable”) is an expression that gets stuck. This is not a crash, although execution comes to a halt without delivering a result. (identifiable infinite loop)

Crashing Definition (Crash). A closed term e crashes iff e ! * BAD Definition (Crash-free Expression) An expression e is crash-free iff 8 C. BAD 2 C, ` C[[e]] :: (), C[[e]] ! * BAD

What to Check? Does function f satisfies its contract t (written f 2 t)? Goal: main 2 {x | True} At the definition of each function f, assuming the given precondition holds, we check 1. No pattern matching failure 2. Precondition of all calls in the body of f holds 3. Postcondition holds for f itself.

How to Check? Given e and t  We construct a term (e B t) (pronounced e “ensures” t)  Prove (e B t) is crash-free. simplify the term (e B t) to e’ and e’ is syntactically safe, then we are done. Theorem 1 e B t is crash-free, e 2 t Theorem 2 simpl (e B t) is syntactically safe ) e B t is crash-free This Talk ESC/Haskell (HW’06)

Syntax of Contracts Full version: x’:{x | x >0} -> {r | r > x’} Short hand: {x | x > 0} -> {r | r > x} k:({x | x > 0} -> {y | y > 0}) -> {r | r > k 5}

Contract Satisfaction e " means e diverges or e ! * UNR

B pronounced ensures C pronounced requires e B {x | p} = case p[e/x] of True -> e False -> BAD e C {x | p} = case p[e/x] of True -> e False -> UNR Example: 5 2 {x | x > 0} 5 B {x | x > 0} = case (5 > 0) of True -> 5 False -> BAD

e B x:t 1 ! t 2 =  v. (e (v C t 1 )) B t 2 [v C t 1 /x] e C x:t 1 ! t 2 =  v. (e (v B t 1 )) C t 2 [v B t 1 /x] e B (t 1, t 2 ) = case e of (e 1, e 2 ) -> (e 1 B t 1, e 2 B t 2 ) e C (t 1, t 2 ) = case e of (e 1, e 2 ) -> (e 1 C t 1, e 2 C t 2 ) Function Contract and Tuple Contract

f :: {x | x > 0} -> {r | True} f x = x f B {x | x > 0} -> {r | True} =( x.x) B {x | x > 0} -> {r | True} = v. ( x.x (v C {x | x > 0})) B {r | True} = v. (case v > 0 of True -> v False -> UNR) g = … f… f C {x | x > 0} -> {r | True} = v. (case v > 0 of True -> v False -> BAD)

Higher-Order Function f1 B ({x | True} -> {y | y >= 0}) -> {r | r >= 0} = … B C B = v 1. case (v 1 1) >= 0 of True -> case (v 1 1) - 1 >= 0 of True -> (v 1 1) -1 False -> BAD False -> UNR f1 :: (Int -> Int) -> Int f1 :: ({x | True} -> {y | y >= 0}) -> {r | r >= 0} f1 g = (g 1) - 1 f2:: {r | True} f2 = f1 (\x -> x – 1)

e B Any = UNR e C Any = BAD f5 :: Any -> {r | True} f5 x = 5 error :: String -> a -- HM Type error :: {x | True} -> Any -- Contract Any Contract

Properties of B and C Lemma1: For all closed, crash-free e, and closed t, e C t 2 t Lemma2: For all e and t, if e 2 t, then (a) e v e B t (b) e C t v e Definition (Crashes-More-Often): e 1 v e 2 iff for all C, ` C[[e i ]] :: () for i=1,2 and (1) C[[e 2 ]] ! * BAD ) C[[e 1 ]] ! * BAD

About 30 Lemmas Lemma [Monotonicity of Satisfaction ]: If e 1 2 t and e 1 v e 2, then e 2 2 t Lemma [Congruence of v ]: e 1 v e 2 ) 8 C. C[[e 1 ]] v C[[e 2 ]] Lemma [Idempotence of Projection]: 8 e, t. e B t B t ≡ e B t 8 e, t. e C t C t ≡ e C t Lemma [A Projection Pair]: 8 e, t. e B t C t v e Lemma [A Closure Pair]: 8 e, t. e v e C t B t

Contributions  Automatic static contract checking instead of dynamic contract checking.  Compared with ESC/Haskell Allow pre/post specification for higher-order function’s parameter through contracts. Reduce more false alarms caused by Laziness and in an efficient way. Allow user-defined data constructors to be used to define contracts Specifications are more type-like, so we can define contract synonym.  We develop a concise notation ( B and C ) for contract checking, which enjoys many properties. We give a new and relatively simpler proof of the soundness and completeness of dynamic contract checking, this proof is much trickier than it looks.  We implement the idea in GHC Accept full Haskell Support separate compilation as the verification is modular. Can check functions without contract through CEG unrolling.