haskell to logic through denotational semantics dimitrios vytiniotis, koen claessen, simon peyton...

22
HASKELL TO LOGIC THROUGH DENOTATIONAL SEMANTICS Dimitrios Vytiniotis, Koen Claessen, Simon Peyton Jones, Dan Rosén POPL 2013, January 2013 1

Upload: anthony-alder

Post on 29-Mar-2015

222 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: HASKELL TO LOGIC THROUGH DENOTATIONAL SEMANTICS Dimitrios Vytiniotis, Koen Claessen, Simon Peyton Jones, Dan Rosén POPL 2013, January 2013 1

1

HASKELL TO LOGIC THROUGH DENOTATIONAL SEMANTICS

Dimitrios Vytiniotis, Koen Claessen,

Simon Peyton Jones, Dan Rosén

POPL 2013, January 2013

Page 2: HASKELL TO LOGIC THROUGH DENOTATIONAL SEMANTICS Dimitrios Vytiniotis, Koen Claessen, Simon Peyton Jones, Dan Rosén POPL 2013, January 2013 1

2

Real programs contain assertionsdimitris@artemis:~/GHC/ghc-head/ghc/compiler/typecheck$ grep -i ASSERT ./*hs ./FamInst.lhs: = ASSERT( isAlgTyCon tycon )./Inst.lhs: ; wrap <- ASSERT( null rest && isSingleton theta )./TcCanonical.lhs: = ASSERT( tyConArity tc <= length tys ) -- Type functions are saturated./TcCanonical.lhs: = ASSERT( not (isKind t1) && not (isKind t2) )./TcClassDcl.lhs: = ASSERT( ok_first_pred ) local_meth_ty./TcClassDcl.lhs: rho_ty = ASSERT( length sel_tyvars == length inst_tys )./TcDeriv.lhs: ASSERT( null sigs )./TcDeriv.lhs: = ASSERT2( equalLength rep_tc_tvs all_rep_tc_args, ppr cls <+> ppr rep_tc )./TcDeriv.lhs: arg_ty <- ASSERT( isVanillaDataCon data_con )./TcEnv.lhs: -> ASSERT( lvl == lvl1 ) id./TcEnv.lhs: TopLevel -> ASSERT2( isEmptyVarSet id_tvs, ppr id $$ ppr (idType id) ) ./TcErrors.lhs: = ASSERT( isEmptyBag insols )./TcErrors.lhs: = ASSERT( not (null matches) )./TcErrors.lhs: = ASSERT( length matches > 1 )./TcEvidence.lhs: | otherwise = ASSERT( arity < n_tys )./TcEvidence.lhs:mkTcForAllCo tv (TcRefl ty) = ASSERT( isTyVar tv ) TcRefl (mkForAllTy tv ty)./TcEvidence.lhs:mkTcForAllCo tv co = ASSERT( isTyVar tv ) TcForAllCo tv co./TcEvidence.lhs:mkTcForAllCos tvs (TcRefl ty) = ASSERT( all isTyVar tvs ) TcRefl (mkForAllTys tvs ty)./TcEvidence.lhs:mkTcForAllCos tvs co = ASSERT( all isTyVar tvs ) foldr TcForAllCo co tvs./TcEvidence.lhs: = ASSERT (tc `hasKey` eqTyConKey)./TcEvidence.lhs: = ASSERT( equalLength tvs cos )./TcExpr.lhs: = ASSERT( not (isSigmaTy res_ty) )./TcExpr.lhs: = ASSERT( notNull upd_fld_names )

(from the GHC type checker)

Page 3: HASKELL TO LOGIC THROUGH DENOTATIONAL SEMANTICS Dimitrios Vytiniotis, Koen Claessen, Simon Peyton Jones, Dan Rosén POPL 2013, January 2013 1

3

This work

Automated static verification of higher-order functional programs

www.github.com/danr/contracts

Tool works on subset of Haskell,uses GHC as frontend

Page 4: HASKELL TO LOGIC THROUGH DENOTATIONAL SEMANTICS Dimitrios Vytiniotis, Koen Claessen, Simon Peyton Jones, Dan Rosén POPL 2013, January 2013 1

4

Our setting

Verify Haskell code: higher-order, lazy but pure

Don’t aim for high expressiveness, go for simple, easy-to-prove (e.g. structural) properties

• Automatically discharge all tedious but simple goals that a programmer has to manually and repeatedly check

Re-use existing technology:• Automated theorem provers (e.g. SMT solvers), model finders• ACL2? Boogie?• Prolog? Property-directed reachability? [Bjorner et al]

No “best” solution yet.Our choice for this work

Page 5: HASKELL TO LOGIC THROUGH DENOTATIONAL SEMANTICS Dimitrios Vytiniotis, Koen Claessen, Simon Peyton Jones, Dan Rosén POPL 2013, January 2013 1

5

Programs and propertiesrisers [] = []risers [x] = [[x]]risers (x:y:ys) = case risers (y:ys) of

[] -> error “urk” (s:ss) -> if x <= y then (x:s):ss else [x]:s:ss

1. can risers crash?2. non-empty input ⟶ non-empty

result?

risers CF && {xs | not (null xs)} -> CF && {ys | not (null ys)}

Syntax of “contracts” (“refinements” more appropriate):

C ::= {x | p} | (x:C1)->C2 | C1 && C2 | CF

Just an ordinary Haskell expression of type Bool

“crash-free”

Page 6: HASKELL TO LOGIC THROUGH DENOTATIONAL SEMANTICS Dimitrios Vytiniotis, Koen Claessen, Simon Peyton Jones, Dan Rosén POPL 2013, January 2013 1

6

Design

module Foof x y = …g x = …

g C-- Preludedata [a] = [] | a : asdata Bool = True | False… Functions over these…

𝑇

𝜑𝑛𝑒𝑔

𝑇 𝑑𝑒𝑓

HaskellSource

First Order Logic

Formulae

Unsatisfiable Contract holds!

HALOtranslation to First Order

Logic

Z3/Equinox/E/Vampire/Paradox

Theorem Prover

Satisfiable Probably contract doesn’t hold but who knows

<loop>Can’t tell anything

Page 7: HASKELL TO LOGIC THROUGH DENOTATIONAL SEMANTICS Dimitrios Vytiniotis, Koen Claessen, Simon Peyton Jones, Dan Rosén POPL 2013, January 2013 1

7

Key idea: let denotational semantics guide us

A λ/case-lifted language

𝐷∞≈ (Π𝑛 1𝐷∞+…+Π𝑛𝑘

𝐷∞+ (𝐷∞⇒𝐷∞ )+1𝑏𝑎𝑑 )⊥Standard

construction

One product of cpos for each constructor of arity

Continuous function space Distinguished

one-element cpo

Lifting

Page 8: HASKELL TO LOGIC THROUGH DENOTATIONAL SEMANTICS Dimitrios Vytiniotis, Koen Claessen, Simon Peyton Jones, Dan Rosén POPL 2013, January 2013 1

8

… and use itself as FOL structure

Logical language:

A translation of expressions to logical terms:𝓔𝓔𝓔

Interpreted as the ‘apply’ combinator in

apply (,_) = apply (,_) = apply(fun(d),d’) = d(d’) apply(_,_) =

Interpreted as injection into the appropriate product

Interpreted as

Page 9: HASKELL TO LOGIC THROUGH DENOTATIONAL SEMANTICS Dimitrios Vytiniotis, Koen Claessen, Simon Peyton Jones, Dan Rosén POPL 2013, January 2013 1

9

Function definitions become FOL axioms

Theory

Theorem:

head (Cons x xs) = xhead _ = error

NB: A Good Thing!

Page 10: HASKELL TO LOGIC THROUGH DENOTATIONAL SEMANTICS Dimitrios Vytiniotis, Koen Claessen, Simon Peyton Jones, Dan Rosén POPL 2013, January 2013 1

10

Axiomatize (some) true facts about

Theorem:

Theory

data List a = Cons a (List a)| Nil

Page 11: HASKELL TO LOGIC THROUGH DENOTATIONAL SEMANTICS Dimitrios Vytiniotis, Koen Claessen, Simon Peyton Jones, Dan Rosén POPL 2013, January 2013 1

11

Higher-order functionshead (Cons x xs) = xhead _ = error

∀ 𝑥 𝑥𝑠 .𝑎𝑝𝑝(h𝑒𝑎𝑑𝑝𝑡𝑟 , 𝑥)=h𝑒𝑎𝑑(𝑥 )

double f x = f (f x)

∀ 𝑥 𝑦 .𝑑𝑜𝑢𝑏𝑙𝑒 (𝑥 , 𝑦 )=𝑎𝑝𝑝 (𝑥 ,𝑎𝑝𝑝 (𝑥 , 𝑦 ))

∀ 𝑥 𝑦 .𝑎𝑝𝑝 (𝑎𝑝𝑝 (𝑑𝑜𝑢𝑏𝑙 𝑒𝑝𝑡𝑟 ,𝑥 ) , 𝑦 )=𝑑𝑜𝑢𝑏𝑙𝑒 (𝑥 , 𝑦 )

Interpreted as the apply(.,.) combinator in

Page 12: HASKELL TO LOGIC THROUGH DENOTATIONAL SEMANTICS Dimitrios Vytiniotis, Koen Claessen, Simon Peyton Jones, Dan Rosén POPL 2013, January 2013 1

12

Refinements denotationally and logically

≙ ≙ Logically

Denotationally

Page 13: HASKELL TO LOGIC THROUGH DENOTATIONAL SEMANTICS Dimitrios Vytiniotis, Koen Claessen, Simon Peyton Jones, Dan Rosén POPL 2013, January 2013 1

13

Soundness via denotational semantics

• Assume that:

• Then:

• By previous theorems:

• … hence:

• … which is equivalent to:

Page 14: HASKELL TO LOGIC THROUGH DENOTATIONAL SEMANTICS Dimitrios Vytiniotis, Koen Claessen, Simon Peyton Jones, Dan Rosén POPL 2013, January 2013 1

14

Automating inductionCurrently support fixpoint induction

add Z y = y add (S x) y = S (add x y)

add CF -> CF -> CF

Assume contract holds for uninterpreted function add_rec add Z y = y add (S x) y = S (add_rec x y)add_rec CF -> CF -> CF---------------------------add CF -> CF -> CF

NB: A sound thing to do by admissibility of contracts

Page 15: HASKELL TO LOGIC THROUGH DENOTATIONAL SEMANTICS Dimitrios Vytiniotis, Koen Claessen, Simon Peyton Jones, Dan Rosén POPL 2013, January 2013 1

15

Admissibility and why it mattersIn Haskell, data types are not inductive. Hence your familiar induction principle is simply unsound!

ones = 1 : ones

f Z = []f (S x) = 1 : f xLemma: forall x. f x ≠ onesProof:• Holds for UNR• Holds for Z• Assume holds for x; then holds for (S x)

Right?

WRONG!Let: u = S uThen: f u = ones

Logical inequality, not admissible!

Page 16: HASKELL TO LOGIC THROUGH DENOTATIONAL SEMANTICS Dimitrios Vytiniotis, Koen Claessen, Simon Peyton Jones, Dan Rosén POPL 2013, January 2013 1

16

Admissibility and inductionAdmissibility

=

If P is true for all elements of a chain, then true for the limit.

Not all predicates are admissible

𝑎𝑑𝑚𝑖𝑠𝑠𝑖𝑏𝑙𝑒 (𝑃 ) 𝑃 (UNR)𝑃 (h )⟹𝑃 (𝐹 h)𝑃 ( 𝑓 𝑖𝑥 𝐹 )

[FixInd ]

Theorem:

All predicates are admissible. Comes for-free!Base contracts are Haskell

functions, and those are continuous!

Page 17: HASKELL TO LOGIC THROUGH DENOTATIONAL SEMANTICS Dimitrios Vytiniotis, Koen Claessen, Simon Peyton Jones, Dan Rosén POPL 2013, January 2013 1

17

Happily implemented on top of GHC API

Z3 rocks for provable properties!

Disclaimer:• 40-80 FOL axioms/problem• Use of fixpoint induction

Page 18: HASKELL TO LOGIC THROUGH DENOTATIONAL SEMANTICS Dimitrios Vytiniotis, Koen Claessen, Simon Peyton Jones, Dan Rosén POPL 2013, January 2013 1

18

More features (and non-features)

More features:• Incremental verification

• Prove spec for “g”, use either the spec or definition of “g”, or both to prove other specifications …

• Some support for lemmas• Mutual (automatic) fixpoint induction• Primitive arithmetic constraints via SMT2 (in Z3)• Experimental features: logical equality, finite unfoldings

Not there:• Pre/post inference, strengthening of IH• Support for counterexamples (see next slide)

Page 19: HASKELL TO LOGIC THROUGH DENOTATIONAL SEMANTICS Dimitrios Vytiniotis, Koen Claessen, Simon Peyton Jones, Dan Rosén POPL 2013, January 2013 1

19

What’s next: counterexamplesUnprovable contracts (because they’re false or we’re incomplete)

Paradox Equinox Z3 Vampire E-proverAnyMorphism.big_sat_app_any_morphism_fail_step P:---- X:---- Z:---- V:---- E:----Loop.sat_id_loop_pred P:0.00 X:0.01 Z:0.01 V:---- E:0.01Loop.sat_id_recursive_true P:---- X:---- Z:---- V:---- E:0.01PredLog.sat_concatMap_cf_missing_step P:---- X:---- Z:---- V:---- E:----PredLog.sat_concatMap_retains_missing_step P:---- X:---- Z:---- V:---- E:----PredLog.sat_flattenAnd_cf_missing_step P:---- X:---- Z:---- V:---- E:----PredLog.sat_flattenAnd_retains_missing_step P:---- X:---- Z:---- V:---- E:----... Recursion.sat_qfac_cf_broken_step P:---- X:---- Z:---- V:---- E:----Recursion.sat_rev_cf_broken_step P:---- X:---- Z:---- V:---- E:----Risers.big_sat_risersBy_nonEmpty_broken2_step P:---- X:---- Z:---- V:---- E:----Risers.big_sat_risersBy_nonEmpty_broken_step P:---- X:---- Z:---- V:---- E:----Risers.sat_risers_broken2_step P:---- X:---- Z:---- V:---- E:----Risers.sat_risers_broken3_step P:---- X:---- Z:---- V:---- E:----Risers.sat_risers_broken_step P:---- X:---- Z:---- V:---- E:----Risers.sat_risers_missing_le_step P:---- X:---- Z:---- V:---- E:----Shrink.big_sat_shrink_lazy_step P:---- X:---- Z:---- V:---- E:----

Timeouts …

We now know why, and how to address this:

stay tuned

Page 20: HASKELL TO LOGIC THROUGH DENOTATIONAL SEMANTICS Dimitrios Vytiniotis, Koen Claessen, Simon Peyton Jones, Dan Rosén POPL 2013, January 2013 1

20

What’s next: usability

Proving is reasonably fast, now explore:• Automatic strengthening of induction hypotheses• Pretty printing models as counterexamples• More induction principles• Testing in larger scale• Interfacing with theorem provers for manual proofs?

Lots of man-hours needed, come help please!

Page 21: HASKELL TO LOGIC THROUGH DENOTATIONAL SEMANTICS Dimitrios Vytiniotis, Koen Claessen, Simon Peyton Jones, Dan Rosén POPL 2013, January 2013 1

Related work Liquid Types [Jhala et al]• Predicate abstraction• Inference• Quantifiers driven by type system

ESC/Haskell [Xu et al]• Contracts are programs• Symbolic

execution/inliningZeno [Sonnex et al]• Automated equality proofs• Clever heuristics• Strict semantics

Catch [Mitchell]• Pattern match errors• Via dataflow analysis

Dafny & Boogie [Leino et al], ACL2

Leon [Suter et al]• Specialized decision

procedure for FP• Good for first-order

F7/F* [Swamy et al]Hoare logic for FP [Regis-Gianas & Pottier]• HO logics• CBV *really* helps

HO model checking, MoChi [Kobayashi et al]• Specialized decision procedures• Lots of techniques stacked• Good for inference, good for

counterexamples

Symbolic execution-based [Tobin-Hochstadt and Van Horn][Xu]• Abstraction, lots of “smaller” queries to

theorem prover

HOLCF-based verification [Huffman]• Reasoning in a very rich logic that contains

formalization of a domain theory• More sophisticated axiomatization, ability to

reason about parametricity and monad laws

Page 22: HASKELL TO LOGIC THROUGH DENOTATIONAL SEMANTICS Dimitrios Vytiniotis, Koen Claessen, Simon Peyton Jones, Dan Rosén POPL 2013, January 2013 1

22

What we did and what I learnt

• We’ve given a semantic basis for the verification of Haskell programs

• We demonstrated that it is implementable

We can verify FP in a simple and robust way:• For this particular case a simple solution seems to do the job.• It appears affordable to use a very precise abstraction of your

program and trust your 2013 theorem proving technology

Thank you for your attention!