Top Banner
Y 0 Y-not Y-knot Y- naught? Greg Morrisett with Aleks N., Ryan W., Paul G., Rasmus P., Lars B.
30

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

Dec 18, 2015

Download

Documents

Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Y 0 Y-not Y-knot Y-naught? Greg Morrisett with Aleks N., Ryan W., Paul G., Rasmus P., Lars B.

Y0 Y-not Y-knot Y-naught?

Greg Morrisett

with Aleks N., Ryan W., Paul G., Rasmus P., Lars B.

Page 2: 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, …)

• 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”

Page 3: Y 0 Y-not Y-knot Y-naught? Greg Morrisett with Aleks N., Ryan W., Paul G., Rasmus P., Lars B.

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.

Page 4: Y 0 Y-not Y-knot Y-naught? Greg Morrisett with Aleks N., Ryan W., Paul G., Rasmus P., Lars B.

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

Page 5: Y 0 Y-not Y-knot Y-naught? Greg Morrisett with Aleks N., Ryan W., Paul G., Rasmus P., Lars B.

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)

Page 6: Y 0 Y-not Y-knot Y-naught? Greg Morrisett with Aleks N., Ryan W., Paul G., Rasmus P., Lars B.

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).

Page 7: Y 0 Y-not Y-knot Y-naught? Greg Morrisett with Aleks N., Ryan W., Paul G., Rasmus P., Lars B.

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.

Page 8: Y 0 Y-not Y-knot Y-naught? Greg Morrisett with Aleks N., Ryan W., Paul G., Rasmus P., Lars B.

Coq Demo

• A few examples…

Page 9: Y 0 Y-not Y-knot Y-naught? Greg Morrisett with Aleks N., Ryan W., Paul G., Rasmus P., Lars B.

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.

Page 10: Y 0 Y-not Y-knot Y-naught? Greg Morrisett with Aleks N., Ryan W., Paul G., Rasmus P., Lars B.

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

Page 11: Y 0 Y-not Y-knot Y-naught? Greg Morrisett with Aleks N., Ryan W., Paul G., Rasmus P., Lars B.

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))

Page 12: Y 0 Y-not Y-knot Y-naught? Greg Morrisett with Aleks N., Ryan W., Paul G., Rasmus P., Lars B.

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) }

Page 13: Y 0 Y-not Y-knot Y-naught? Greg Morrisett with Aleks N., Ryan W., Paul G., Rasmus P., Lars B.

Problem Continued

• Next, define: f(p:T):T = {g;q } where g 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 some m, (fst p) diverges, so pick n=m+1.

• Finally, take F := ffix(f)– snd(F) proves fst(F) diverges– but fst(F) does not!

Page 14: Y 0 Y-not Y-knot Y-naught? Greg Morrisett with Aleks N., Ryan W., Paul G., Rasmus P., Lars B.

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.)

Page 15: Y 0 Y-not Y-knot Y-naught? Greg Morrisett with Aleks N., Ryan W., Paul G., Rasmus P., Lars B.

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.

Page 16: Y 0 Y-not Y-knot Y-naught? Greg Morrisett with Aleks N., Ryan W., Paul G., Rasmus P., Lars B.

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?

Page 17: Y 0 Y-not Y-knot Y-naught? Greg Morrisett with Aleks N., Ryan W., Paul G., Rasmus P., Lars B.

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

Page 18: Y 0 Y-not Y-knot Y-naught? Greg Morrisett with Aleks N., Ryan W., Paul G., Rasmus P., Lars B.

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].

Page 19: Y 0 Y-not Y-knot Y-naught? Greg Morrisett with Aleks N., Ryan W., Paul G., Rasmus P., Lars B.

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)

Page 20: Y 0 Y-not Y-knot Y-naught? Greg Morrisett with Aleks N., Ryan W., Paul G., Rasmus P., Lars B.

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)

wheremapsto(A:Set)(h:heap)(x:loc)(v:A) := (h x) = Some(mkDynamic {A;v}}

Page 21: Y 0 Y-not Y-knot Y-naught? Greg Morrisett with Aleks N., Ryan W., Paul G., Rasmus P., Lars B.

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]. whereupdate(h:heap)(x:loc)(A:Set)(v:A):heap :=

fun y => if (eq_loc x y) then Some(Dynamic{A,v})

else h y

Page 22: Y 0 Y-not Y-knot Y-naught? Greg Morrisett with Aleks N., Ryan W., Paul G., Rasmus P., Lars B.

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].

Page 23: Y 0 Y-not Y-knot Y-naught? Greg Morrisett with Aleks N., Ryan W., Paul G., Rasmus P., Lars B.

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].

Page 24: Y 0 Y-not Y-knot Y-naught? Greg Morrisett with Aleks N., Ryan W., Paul G., Rasmus P., Lars B.

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))))).

Page 25: Y 0 Y-not Y-knot Y-naught? Greg Morrisett with Aleks N., Ryan W., Paul G., Rasmus P., Lars B.

Type Inferred for Swapforall (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!

Page 26: Y 0 Y-not Y-knot Y-naught? Greg Morrisett with Aleks N., Ryan W., Paul G., Rasmus P., Lars B.

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.

Page 27: Y 0 Y-not Y-knot Y-naught? Greg Morrisett with Aleks N., Ryan W., Paul G., Rasmus P., Lars B.

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.)

Page 28: Y 0 Y-not Y-knot Y-naught? Greg Morrisett with Aleks N., Ryan W., Paul G., Rasmus P., Lars B.

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.

Page 29: Y 0 Y-not Y-knot Y-naught? Greg Morrisett with Aleks N., Ryan W., Paul G., Rasmus P., Lars B.

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.

Page 30: Y 0 Y-not Y-knot Y-naught? Greg Morrisett with Aleks N., Ryan W., Paul G., Rasmus P., Lars B.

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