sound haskell dana n. xu university of cambridge joint work with simon peyton jones microsoft...

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

Upload: loren-houston

Post on 04-Jan-2016

215 views

Category:

Documents


0 download

TRANSCRIPT

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

Sound Haskell

Dana N. Xu

University of Cambridge

Joint work with Simon Peyton Jones

Microsoft Research CambridgeKoen Claessen

Chalmers University of Technology

Page 2: 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]->Intf 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] -> ahead (x:xs) = xhead [] = error “empty list”

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

Types>> > > > > Contracts >> > > > >

head (x:xs) = x

head :: [Int] -> Int

…(head 1)…

head :: {x | not (null xs)} -> {r | True}

…(head [])…

Bug!

Bug!Contract

(original Haskell boolean expression)

Type not :: Bool -> Boolnot True = Falsenot False = True

null :: [a] -> Boolnull [] = Truenull (x:xs) = False

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

Preconditionshead :: {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!

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

Expressiveness of the Specification Language

data T = T1 Bool | T2 Int | T3 T T

sumT :: T -> IntsumT :: {x | noT1 x} -> {r | True}sumT (T2 a) = asumT (T3 t1 t2) = sumT t1 + sumT t2

noT1 :: T -> BoolnoT1 (T1 _) = FalsenoT1 (T2 _) = TruenoT1 (T3 t1 t2) = noT1 t1 && noT1 t2

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

Expressiveness of the Specification LanguagesumT :: T -> IntsumT :: {x | noT1 x} -> {r | True}sumT (T2 a) = asumT (T3 t1 t2) = sumT t1 + sumT t2

rmT1 :: T -> TrmT1 :: {x | True} -> {r | noT1 r}rmT1 (T1 a) = if a then T2 1 else T2 0rmT1 (T2 a) = T2 armT1 (T3 t1 t2) = T3 (rmT1 t1) (rmT1 t2)

For all crash-free t::T, sumT (rmT1 t) will not crash.

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

Functions without Annotationsdata T = T1 Bool | T2 Int | T3 T T

noT1 :: T -> BoolnoT1 (T1 _) = FalsenoT1 (T2 _) = TruenoT1 (T3 t1 t2) = noT1 t1 && noT1 t2

(&&) True x = x(&&) False x = False

No abstraction is more compact than the function definition itself!

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

Higher Order Functions

all :: (a -> Bool) -> [a] -> Boolall f [] = Trueall 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’

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

Contracts for higher-order function’s parameterf1 :: (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 >= 0Error: f2 calls f1 which fails f1’s precondition

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

Lazinessfst (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) -> IntfstN :: ({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

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

Various Exampleszip :: [a] -> [b] -> [(a,b)]zip :: {xs | True} -> {ys | sameLen xs ys} -> {rs | sameLen rs xs }

sameLen [] [] = TruesameLen (x:xs) (y:ys) = sameLen xs yssameLen _ _ = False

f91 :: Int -> Intf91 :: { n <= 101 } -> {r | r == 91 }f91 n = case (n <= 100) of

True -> f91 (f91 (n + 11)) False -> n – 10

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

Sortingsorted [] = Truesorted (x:[]) = Truesorted (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

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

Contract Synonymtype 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

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

What we can’t dog1, g2 :: Ok -> Okg1 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!

Crash!

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

LanguageSyntax

following Haskell’slazy semantics

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

Two special constructors BAD is an expression that crashes.error :: String -> aerror s = BAD

head (x:xs) = xhead [] = 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)

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

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

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

What to Check?Does function f satisfies its contract t (written f2 t)?

Goal: main 2 {x | True}

At the definition of each function f,assuming the given precondition holds,we check1. No pattern matching failure2. Precondition of all calls in the body of f holds3. Postcondition holds for f itself.

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

How to Check?Given e and t We construct a term (eBt) (pronounced e “ensures” t) Prove (eBt) is crash-free.

simplify the term (eBt) to e’ and e’ is syntactically safe, then we are done.

Theorem 1eBt is crash-free , e 2 t

Theorem 2simpl (eBt) is syntactically safe ) eBt is crash-free

This Talk

ESC/Haskell (HW’06)

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

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}

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

Contract Satisfaction

e" means e diverges or e !* UNR

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

B pronounced ensuresC pronounced requires

e B {x | p} = case p[e/x] of

True -> eFalse -> 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

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

e B x:t1 ! t2 = v. (e (vC t1)) B t2[vCt1/x]

e C x:t1 ! t2 = v. (e (vB t1)) C t2[vBt1/x]

e B (t1, t2) = case e of (e1, e2) -> (e1 B t1, e2 B t2)

e C (t1, t2) = case e of (e1, e2) -> (e1 C t1, e2 C t2)

Function Contract and Tuple Contract

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

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)

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

Higher-Order Function

f1 B ({x | True} -> {y | y >= 0}) -> {r | r >= 0}= … B C B= v1. case (v1 1) >= 0 of True -> case (v1 1) - 1 >= 0 of True -> (v1 1) -1 False -> BAD False -> UNR

f1 :: (Int -> Int) -> Intf1 :: ({x | True} -> {y | y >= 0}) -> {r | r >= 0}f1 g = (g 1) - 1

f2:: {r | True}f2 = f1 (\x -> x – 1)

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

e B Any = UNRe C Any = BAD

f5 :: Any -> {r | True}f5 x = 5

error :: String -> a -- HM Typeerror :: {x | True} -> Any -- Contract

Any Contract

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

Properties of B and CLemma1:For all closed, crash-free e, and closed t,e C t 2 t

Lemma2:For all e and t, if e2 t, then (a) e v e B t(b) e C t v e

Definition (Crashes-More-Often):e1 v e2 iff for all C, ` C[[ei]] :: () for i=1,2 and(1) C[[e2]] !* BAD ) C[[e1]] !* BAD

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

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

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

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.