1 / 30

Y 0 Y-not Y-knot Y-naught?

Y 0 Y-not Y-knot Y-naught?. Greg Morrisett with Aleks N., Ryan W., Paul G., Rasmus P., Lars B. ESC, JML, Spec#, …. Need a different spec language: “pure” boolean expressions: length(x)==42 “modeling” types (e.g., pure lists, sets, …)

noelle
Download Presentation

Y 0 Y-not Y-knot Y-naught?

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Y0 Y-not Y-knot Y-naught? Greg Morrisett with Aleks N., Ryan W., Paul G., Rasmus P., Lars B.

  2. ESC, JML, Spec#, … • Need a different spec language: • “pure” boolean expressions: length(x)==42 • “modeling” types (e.g., pure lists, sets, …) • If the implementation is pure, can’t use it in the specs! • x.f versus \old(x.f) • What if Simplify can’t prove something? • Ignore (e.g., arith, modifies clause): unsound • Rewrite code? • Weaken spec? • Not really modular: can’t write “app” or “map”

  3. DML, ATS, Omega, … • Introduce different spec language. • Again, a separate “pure” language • To capture all properties of lists, you’d have to index them with well, lists. • Can’t talk about properties of effectful computations (or limited capacity). • ATS can build proofs, but it’s awkward.

  4. Coq, PRL, Isabelle, … • Ynot starts with Coq as the basic language: • [co]inductive definitions, h.o. functions, polymorphism, h.o. predicates, proofs, … • Strong support for modularity • e.g., can package up and abstract over terms, types, predicates, proofs, in a uniform fashion. • can prove that, e.g., append is associative and rev(rev(x)) = x, etc. after defining it. • But huge drawback: • No effects (non-term, IO, state, recursive types, etc.) • Not a strong phase separation

  5. Quick Coq • Set : (think * in Haskell) • nat, bool, functions from sets to sets, … • inductive set definitions (e.g., list) • co-inductive set definitions (e.g., stream) • Prop : • Think of nat->Prop as a subset of nat. • Equality, /\, \/, etc. • [co-]inductive definitions (e.g., judgments)

  6. Refinement • Can form mixed products & sums • {n:nat | n >= 42} is a pair of a nat and a proof that this nat is >= 42. • Array subscript: forall (A:Set)(n:nat) (v:vector n A) (j:nat), (j < n) -> A • Can extract Ocaml or Haskell code. • “erase” Prop objects (really, replace with unit).

  7. Purity • We want to pull the Curry-Howard isomorphism to represent a proof of Prop P as a term with type P. • Reduce proof-checking to type-checking. • Should be no term with type False. • If we added recursive functions, recursive types, exceptions, or refs, we could code up a term of type False. • So everyone forgoes these “features” in their type theory.

  8. Coq Demo • A few examples…

  9. Ynot and HTT • We add a new type constructor, IO A • As in Haskell, encapsulate effectful computations. • We’re not pretending that IO False is a proof of false -- rather, it’s a computation which when run, if it terminates, then it produces a proof of False. • Of course, it can’t terminate.

  10. Ynot IO: Attempt #1 • IO : Set -> Set • return: forall (A:Set), A -> IO A • bind : forall (A B:Set), IO A -> (A -> IO B) -> IO B • ffix : forall (A:Set), (IO A -> IO A) -> IO A

  11. Reasoning about IO • steps : IO A -> IO A -> Prop. • steps_ret_bnd : forall (A B:Set)(v:A)(f:A->IO B), steps (bind (ret v) f) (f v). • steps_bnd_cong : forall (A B:Set)(c1:IO A)(f:A->IO B), (steps c1 c2) -> (steps (bind c1 f) (bind c2 f)). • steps_ffix : forall (A:Set)(f:IO A->IO A), steps (ffix f) (f (ffix f))

  12. Problem: • We have added a way to prove False! • Sketch of problem (not quite right): • Define diverges(c:IO A):Prop • Define stepsn c1 c2 n as c1 steps to c2 in no more than n steps. • Define diverges c as there’s no n and v such that stepsn c (ret v) n. • Define T := { f : nat -> IO nat | for some n, diverges(f n) }

  13. Problem Continued • Next, define:f(p:T):T = {g;q } whereg n = if n = 0 then 0 else (fst p)(n-1)and q argues that for some n, g diverges: (snd p) provides a proof that for somem, (fst p) diverges, so pick n=m+1. • Finally, take F := ffix(f) • snd(F) proves fst(F) diverges • but fst(F) does not!

  14. How to Fix? • One option: restrict IO to admissible types. • In essence, we need closure conditions to ensure that fixed-points preserve typing. • Comprehensions (subsets of types) are problematic in general. • Crary shows some sufficient syntactic criteria for determining admissibility. • Another option: don’t expose steps or any other axiom on IO terms. • Well, we can expose some (the monad laws.)

  15. No Axioms? • Can interpret IO A := unit. • ret v = tt, bind v f = tt, ffix f = tt • Without any axioms, can’t tell the difference! • Allows us to establish consistency of logic. • a trivial model. • Aleks is then able to prove preservation and progress for the real operational semantics. • But we have limited reasoning about computations within the system.

  16. Extending IO • We want to handle the awkward squad: • Refs, IO, exceptions, concurrency, … • So need to scale IO A. • Today: refs, exceptions • Tomorrow: IO • Quite a ways off: concurrency?

  17. Heaps & Refs in Ynot We model heaps in Coq as follows: • loc : Set • loc_eq:(x y:loc)->{x=y}+{x<>y} • can model locs as nats. • dynamic := {T:Set; x:T} • heap := loc -> option dynamic • NB: heaps aren’t “Set” w/out impredicative

  18. IO Monad • Pre := heap -> Prop • Post(A:Set) := A -> heap -> heap -> Prop • IO: forall (A:Set), Pre -> Post A -> Post exn -> Set. • Implicit Arguments IO [A].

  19. Return & Throw ret : forall (A:Set)(x:A), IO (fun h => True) (fun y old h => y=x /\ h=old) (fun e old h => False) Implicit Arguments ret[A]. throw : forall (A:Set)(x:exn), IO (fun h => True) (fun y old h => False) (fun e old h => e=x /\ h=old)

  20. Reading a Location read : forall (A:Set)(x:loc), IO (fun h => exists v:A,mapsto h x v) (fun y old h => old = h /\ mapsto h x v) (fun e old h => False) where mapsto(A:Set)(h:heap)(x:loc)(v:A) := (h x) = Some(mkDynamic {A;v}}

  21. Writing a Location write : forall (A:Set)(x:loc)(v:A), IO (fun h => exists B, exists w:B, mapsto h x w) (fun y old h => y = tt /\ h = update old x A v) (fun e old h => False) Implicit Arguments write[A]. where update(h:heap)(x:loc)(A:Set)(v:A):heap := fun y => if (eq_loc x y) then Some(Dynamic{A,v}) else h y

  22. Bind bind : forall (A B:Set)(P1:Pre)(Q1:Post A)(E1:Post exn) (P2:A->Pre)(Q2:A->Post B)(E2:A->Post exn), (IO A P1 Q1 E1) -> (A -> IO B P2 Q2 E2) ->IO B (fun h => P1 h /\ (forall x m,(Q1 x h m) -> P2 m)) (fun y old m => exists x m, (Q1 x old m) /\ (Q2 y m h)) (fun e old m => (E1 e old m) \/ (exists x m, (Q1 x old m) /\ (E2 e m h))) Implicit Arguments bind [A B P1 Q1 E1 P2 Q2 E2].

  23. Using Bind Definition readThen := fun (A B:Set)(x:loc) (p:A->pre)(q:A->post B) (e:A->post exn) (c:forall y:A, IO (p y) (q y) (e y))=> bind (read A x) c. Implicit Arguments readThen [A B p q e].

  24. Example: Definition swap := fun (A B:Set)(x y:loc) => (readThen x (fun (xv:A) => readThen y (fun (yv:B) => writeThen x yv (writeThen y xv (ret tt))))).

  25. Type Inferred for Swap forall (A B : Set) (x y : loc 1), IO (fun i : heap => (fun i0 : heap => exists v : A, mapsto i0 x v) i /\ (forall (x0 : A) (m : heap), (fun (y0 : A) (i0 m0 : heap) => mapsto i0 x y0 /\ m0 = i0) x0 i m -> (fun (xv : A) (i0 : heap) => (fun i1 : heap => exists v : B, mapsto i1 y v) i0 /\ (forall (x1 : B) (m0 : heap), (fun (y0 : B) (i1 m1 : heap) => mapsto i1 y y0 /\ m1 = i1) x1 i0 m0 -> (fun (yv : B) (i1 : heap) => (fun i2 : heap => exists B0 : Set, exists z : vector B0 1, mapsto_vec i2 x z) i1 /\ (forall (x2 : unit) (m1 : heap), (fun (_ : unit) (i2 m2 : heap) => m2 = update i2 x yv) x2 i1 m1 -> (fun (_ : unit) (i2 : heap) => (fun i3 : heap => exists B0 : Set, exists z : vector B0 1, mapsto_vec i3 y z) i2 /\ (forall (x3 : unit) (m2 : heap), (fun (_ : unit) (i3 m3 : heap) => m3 = update i3 y xv) x3 i2 m2 -> (fun _ : unit => nopre) x3 m2)) x2 m1)) x1 m0)) x0 m)) pre-conditiononly!

  26. Do do : forall (A:Set)(P1:Pre)(Q1:Post A)(E1:Post exn) (P2:Pre)(Q2:Post A)(E2:Post exn), (IO A P1 Q1 E1) -> (forall h,(P2 h) -> (P1 h)) -> (forall y old m, (p2 old) -> (Q1 y old m) -> (Q2 y old m)) -> (forall e old m, (p2 old) -> (E1 y old m) -> (E2 y old m)) -> IO A P2 Q2 E2. Implicit Arguments do [A P1 Q1 E1]. Essentially, the rule of consequence.

  27. Ascribing a Spec to Swap Program Definition swap_precise : forall (A B:Set)(x y:loc 1), IO (fun i => exists vx:A, exists vy:B, mapsto i x vx /\ mapsto i y vy) (fun (_:unit) i m => exists vx:A, exists vy:B, m = update (update i x vy) y vx) (fun _ _ _ => False) := fun A B x y => do (swap A B x y) _. Followed by a long proof.(can be shortened with combination of key lemmas and tactics.)

  28. Another Example: Definition InvIO(A:Set)(I:Pre) := IO I (fun (_:A) _ m => I m) (fun (_:exn) _ m => I m). Program Fixpoint mapIO(A B:Set)(I:pre) (f:A -> B -> InvIO B I (acc:B)(x:list A) {struct x} : InvIO B I := match x with | nil => do (ret acc) _ | cons h t => do (bind (f h acc) (fun acc2 => mapIO A B p q e pf f acc2 t)) _ end.

  29. Advantages • For pure code: • Can use refinements a la DML/ATS • Or, can reason after the fact • E.g., can prove append associative without having to tie it into the definition. • Modeling language is serious • e.g., heaps are defined in the model. • Abstraction over values, types, specifications, and proofs (i.e., compositional!) • If you stick to simple types, no proofs.

  30. Key Open Issues • Proofs are still painful. • Need to adapt automation from ESC • Need analogues to object invariants, ownership, etc. for mutable ADTs. • Separation logic seems promising (next time). • IO and other effects • Need pre/post over worlds (heaps are just a part.) • Better models? • Predicate transformers seem promising • Rasmus & Lars working on denotational model

More Related