Document 17864784

advertisement
>> Bruce: Good afternoon, everyone. I'm Bruce Delano [phonetic], and
I'm very pleased to introduce Nada Amin who has been spending, well, a
week with us and will spend this week as well. But before then she has
done a lot of work with using Dafny and she's now learning how to hack
in the Dafny sources as well to add the improvements that she would
like. Now, Nada has like a developer history as well from having
worked at Microsoft as an intern some number of years ago. And worked
at Google as a developer as well, right, in Zurich and is now at EPFL
studying for her Ph.D. with Martin Odersky. So take it away.
>> Nada Amin: Thank you. Thank you for inviting me to MSR. It's been
a lot of fun to dabble with Dafny internal. It's going to be from a
user perspective. I've been using Dafny to do meta theory of
programming languages and I've done both textbook examples and research
level paper examples and also used it in my own research where I wasn't
really sure where I was going and using Dafny to guide me a little bit
both in the design and in the proofs. But for this talk I'll start
with the textbook example, which is modeling the simply typed lamda
calculus and mechanically proving the semantic types on this and what I
hope to convey here is that in terms of modeling Dafny doesn't really
bring so much more than [indiscernible] talk but it's when you do the
proofs that you get a lot of mileage out of using Dafny.
So first we'll still look at the model, and I'm starting to define
some -- here I'm defining a data type for option which is really just
kind of like the maybe [indiscernible] or something like this, and I'm
using it because I often want to use, have functions that sometimes
return a result and sometimes not. Like the step function of
operational semantics or the typing function. Not every term has a
type. So I'll be using the option one for this.
And then for my base types for the simply typed lambda calculus, I'll
have this opaque base type to start with. So this is just some type
that you can't really match anything else against except itself. And
then recursively you define this arrow type which takes a parameter
type and a return type. T 2.
And then for the terms, we have variables, application and abstraction.
And actually here I should just say the abstraction also takes the type
T. Okay. So in terms of -- yeah? Is there any question.
>>:
No, no.
>>: I have a question. Is the variable going to be represented by
just concrete names or ->> Nada Amin: Yeah, I'm using integers as concrete names. I'm not
using any fancy encoding. For the purpose of this calculus this is
going to be enough because we're only dealing with close terms so we
don't have any issues with variable capture. But of course if we want
to extend this to other settings like, for example, in system F where
you also have type applications and here you can have capture, it will
need to -- we'll need to be a bit more sophisticated. But here I'm
using the simple encoding and this is also the same as the encoding
used in the COC [phonetic] development from foundations of software.
Okay. So in terms of operational semantics, we just define what is a
value in our language, and for here we'll say that any lambda, any
lambda abstraction is a value. And then here there's some boilerplate
in terms of defining free variables and substitution. So the
interesting case is really that so F of V says that it computes the set
of fee variables of term T and interesting case is if we have a
variable then we just return its ID in the set. If we have an
abstraction, then we compute the fee variables of the body but we
remove the bound variable X because it's not free. It's bound. And
then the other case are just recursing over and unioning the free
variables we find.
>>: So with that, the union have to define all the set what they are
and what they are not. And what you get here --
>> Nada Amin: So Dafny has a primitive for a set and it knows already
about -- it has already some axioms about sets. So it knows things
such that if you remove X from the set here, then this whole, this set
here will not have X anymore in terms of variables. Does this answer
your question?
>>:
Okay.
>> Nada Amin: Any more questions? And then substitution is also a bit
boilerplaty but it's the same pattern. So if we have a variable X
prime, so just to recap substitution says that we have a term T. And
we replace all three occurrences of X with S, another term S. And
interesting case is if we have a free variable X prime then we just go
ahead and do the substitution if it matches, if the variable matches.
Otherwise we leave the term unchanged. And here this is where Nikil's
[phonetic] comes in because we're only dealing with -- we're only
dealing with cases where S is closed. So this is okay.
In general, if S can have free variables, let's say S had this variable
X prime, then we're doing the substitution -- we have S here, and this
X prime would capture the free variable X prime that is in S. So we're
assuming that S is closed and this will show up in the proofs as well.
But for now we're not worrying about it so much. And then application
is just a recursive case. So with this we can define -- yes?
>>:
Is it easily fixed?
Right?
>> Nada Amin:
Uh-huh.
>>: You don't need more fancy encoding, kind of just remove, what you
have to do, remove the X --
>> Nada Amin: So what I could do is this is a bound variable. This is
a bound variable. So I could rename it to something else. But then if
you start to do renaming, you could do that, but then you also need a
way to compare terms that have different names but are still
equivalent.
>>:
That's really difficult.
>> Nada Amin: That's a FI equivalence. But it's doable. I think
using a different encoding might be useful. In COC they have this
library for locally nameless encoding where you use [inaudible] indices
for when you're in a local setting, with bound variables, but in a
global setting you still use these names. So we could do things like
this. I've played with this. But, yeah, for this example I'm glossing
over that.
>>: You could still use concrete names and just alpha convert T before
substituting, but you don't necessarily need to reason about alpha
equivalence distribution type tactic.
>> Nada Amin: Maybe not in this case but I was thinking ahead of cases
where you would need to.
>>:
You can do renaming --
>> Nada Amin: No, it's fine. I don't mind interruptions, but I'll
show later how you can do this as well like this. So for the reduction
relation. So here we see that if we compare with any other language we
have less specificities for pattern matching because we can't really
have nested pattern matching like here I have to explicitly have these
statements but this is basically saying if I have an application and
the function part is an abstraction and the argument part is a value
then I can go ahead and do a better reduction. So the substitution.
Otherwise, these are just congruent cases. Again, I can step on the
function side or I can step on the argument side. And I chose to make
my function deterministic. Anyway, it's going to be deterministic
because I'm using these if statements but I'm just being explicit about
the fact that I'm only stepping on the argument when F is already a
value.
Okay. And then you can define a multi-step relation. And this is
really if you look at the step function and think of it as -- it's a
partial function. So think of it as a relation and then this is really
just a reflexive transitive closure of that relation. And here we're
taking N for the number of steps we're doing. Okay. So we can do some
examples and this one Dafny figures out automatically. And now on to
typing.
>>:
[indiscernible].
>> Nada Amin: Yeah. So this is just saying if I write it in and I
have lambda X which takes a base type and returns X and then I'm
applying this to lambda X then that just returns lambda XVX.
>>:
The first name is BLB [phonetic].
>> Nada Amin:
>>:
Is this the recent extract?
>> Nada Amin:
>>:
No, not yet.
This one was proved automatically.
This is just one step.
>> Nada Amin:
zero.
>>:
Yeah, you're right.
This is just one step.
N just has to be greater than
But for something more of a [indiscernible] function application?
>> Nada Amin: Yeah, uh-huh. This was just to -- it's like writing a
test with -- yeah. All right. So typing. So first I'm using maps.
This is also a Dafny data type. Internal data type to represent a
partial map from variable names to types. And you can look things up
in the map. So I'm just -- and you can extend the map as well. So I'm
going to use these abstractions over it. And the typing relation is
syntax-directed. So we have one case for absent an app and here we see
that, okay, it's not that pretty because of this [indiscernible] but
that's why I've put these checks a bit here so that they don't affect
the main flow, which is here. So for a variable we just look it up in
the context. For an abstraction, we type the body in extended context,
and then return an arrow type where the type of the body is in the
result of the arrow. And then for application we just type the
function and the argument and we check that the function is actually an
arrow and it agrees with the argument, and then we return the result of
the function.
Okay.
So now we're done with our model.
>>: Can I ask a question, you chose to write the typing relation as a
function in the simply typed lambda calculus is easily natural. But
one would normally write it as a relational --
>> Nada Amin: Yeah, I can also do this. In my own research work I've
mostly used relations. And it makes more sense because even there
sometimes I wasn't sure if something is decidable then you don't have a
choice which is a relation. And you can also work with the undecidable
things if you also have a step index and things like this. And what's
nice in Dafny is that mutual induction works really nicely. Even if
you have a step index, you can -- it makes it really easy to do mutual
induction on things.
>>:
You have a bar here --
>> Nada Amin:
>>:
Of the body.
>> Nada Amin:
>>:
It's just a variable.
Oh the vary -- yeah.
Let's see.
Oh, wow.
>> Nada Amin:
>>:
Varies.
You have the write decrease as T [phonetic].
>> Nada Amin:
>>:
CR 2 [phonetic].
[indiscernible].
>> Nada Amin:
>>:
Semantic of what, sorry?
Yes, I guess it's getting.
Not very smart about it.
>> Nada Amin: It's getting confused because here we're extending the
context. So the context is not decreasing.
>>:
But the second is always decreasing.
>> Nada Amin:
But it has some default so here --
>>:
Complaint services [phonetic].
>>:
What if you had -- [cross talk] .
>> Nada Amin: If I switched the parameter it would have worked.
Because it works ->>:
By default it's -- graphic of the argument in the order given.
>>:
Sorry I was still falling off my chair.
>> Nada Amin: So here are some examples, again. This is just testing.
Not proofs yet. And here we actually have to do more work in some
cases. And the reason is that Dafny just does a bit of unfolding and
not much. I'm finally understanding this, but we have some ideas on
how to change this so that you wouldn't need to assert the intermediate
steps. But anyway that was just to give some examples. We don't need
to go to them in detail.
I want to get to the type ST properties.
going to ->>:
Why is it you're working using integers instead of variables.
>> Nada Amin:
>>:
Because Dafny doesn't have strings.
Yeah.
The integer --
>> Nada Amin:
>>:
Like names, you mean?
Yes.
>> Nada Amin:
>>:
For type ST [phonetic] we're
Yeah.
Integer terms of --
>> Nada Amin: Okay. So for the type ST theorems we're going to do
syntax on this. So progress and preservation. And the way to read
this ghost method is really just something that's there for
verification so it doesn't get compiled into code. And the way to read
it is that it requires clauses are like hypothesis of your demo or
theorem. And insure clause are like conclusions.
So here we're saying if term T has a type and the empty context, then
either it's a value or it's steps. It can take some steps. First
let's just look at how this is done on paper and COC to prove this. Is
this readable? So on paper you really would do a induction on the
typing variation. There are a few cases it's pretty straightforward,
but you have to still reason through them.
In COC, this is how it would look. It's a fairly long proof. And
already it's using some automation with these dot, dot, dot. And,
yeah, so that's the end of the proof.
>>:
So magic things.
You have to destruct or --
>> Nada Amin: Yes, so you need to understand this tactic language.
So, for example, this is saying ->>:
Destruct.
>> Nada Amin: Yeah. Yeah, this is doing induction on the derivation,
and then when here we're going to use -- it's hard to read without
having the context, the interactive context of the proof. But anyway I
wanted to give you a flavor what it looks.
>>: The interesting thing is you have to know a lot about the
[indiscernible] engine to guide it in the right way. That's what I
call the magic words like [indiscernible] or diversion or something,
guide it along.
>> Nada Amin:
[laughter]
[applause]
And this is how it looks in Dafny.
Nothing.
>> Nada Amin: So not all proofs are going to be that easy. But this
one it figured out automatically. Because, yeah, it's just an
induction on the typing derivation, so it could fill this out.
>>:
Induction on the piping derivation or on the term?
>> Nada Amin: I think here it's doing it on the term. But what
happens is it has this hypo thesis, which is the type. So at the end
it can really, when it's in the -- say when it's the abstraction case,
it can use the induction hypo thesis from, that comes from this typing
the full abstraction. So at the end it's equivalent to doing a typing
derivation on the term, because you're kind of doing a case analysis.
I'll show another example of this data.
>>: [indiscernible] comparison because when you show it
[indiscernible] you say it's a text [indiscernible] [indiscernible]
everything and nothing is automatic --
>> Nada Amin: That's fair but it's kind of the default way to do
things. If you want to go fancy in COC, it actually takes some
thinking to really automate and do proofs that are modular. But in
Dafny it kind of comes for free.
Okay. So now we're going to do preservation using the substitution
lemma first. And here are just some lemmas that I also took from the
textbook. And Dafny proved them automatically. So here I had to give
a hint to Dafny that says do an induction where you generalize over
both C and T. And the reason -- whoops. The reason you need to
generalize over the context as well is because you have the abstraction
case. So anyway this says that if X is a free variable of T, and T has
some type and some context, then this context definitely has -definitely binds X.
>>: So I was wondering about the process by which you arrived at these
ways of stating things. So you wrote the progress thing where you
weren't surprised --
>> Nada Amin:
I was surprised.
>>: When you got to the lemma free context how did you discover that
maybe you tried the first time to see if it would go through
automatically and it probably didn't.
>> Nada Amin: Okay. So let's remove this. So here it's going to
complain that something -- and this one is actually a bit of a tricky
one. There's a bit of a bug. So I'm just going to -- I mean, I'm just
going to go through it but just gloss over this bug. So here it says
it doesn't know how to proof -- oh. Not yet.
>>:
Still working.
>> Nada Amin: Yeah. Wait. That worked. Oh, that's weird. Okay. So
this one is a bit buggy. But, yeah, this doesn't make much sense if
you repeat -- but in general I'll show how ->>:
Showed the error message?
>> Nada Amin:
>>:
Yeah, so it just doesn't know.
Oh, right.
>>: So if you add insures, maybe Dafny gets help just a little bit
more in how to find --
>> Nada Amin: Yeah, I think so. There's something strange going on
with this example. But usually it's a bit more straightforward. So
I'll show some examples later of how you do some derivations. Okay.
So then we're only interested in close terms. So this is how we define
closed terms. Just saying that X -- for any variable X it's not in the
free variables of T.
>>:
Why don't you just say F of VT --
>> Nada Amin: It could have been simpler. Yeah. But anyway I wanted
to do a proof by contradiction. So here you go. So while I guess I
could have done it in the other way. But so here I'm seeing a
corollary of the previous thing is that if you are typeable in MT
context then you're closed. And I'm doing this by I have to reproduce
this pattern here. So I have this for all parallel statement kind of
that says, well, for all X we're going to ensure that X is not in the
free variable of T. And I'm doing this by first assuming that it is.
And then showing that you get a contradiction because if it's in the
free variable of T, then by the previous lemma we know that it must be
in this context but this context is empty. So I think maybe if I tried
to change it as you said, this proof would also look simpler. Okay.
So one more it's just a context invariance. I'm not -- again it's one
that's proved automatically. It's just saying that if C and C prime
agree on all free variables of T, then they should agree on the type as
well. Okay. So now this is we're coming to the hardest part which is
the substitution lemma. And this is also notoriously tricky in many
calculus once you do extensions. So this says that basically
substitution preserves typing. And this statement is actually a bit
hard to read. The reason is that I don't want to be adding extra
variables here. So I can't really -- the only way I have of referring
to this type, which I know it has some type and the only way I have of
referring to it is by this expression. Like this dot get. But this
basically says that if S has some type S capital S in an empty context
and T has type T in a context extended with X having type S, then if
you do the substitution you have the same type as well. And really the
only interesting case when we did the model was for variable and
application. So this is the only cases where we have to guide Dafny a
little bit. And we're using the previous lemmas in key places. Okay.
>>:
So you mean you have to guide Dafny by writing the insert or by --
>>:
Exactly.
>>:
Or the responsive terms.
>> Nada Amin: So the way this works, let's say I comment this out.
Well, okay, yeah, so then it's complaining and the squiggly is here,
which means that it's really like a different case that is complaining
about. So then I can try to figure this out by doing like say TF, for
example, this is the problematic case. And then I do FTVAR. Is this
the problematic case? And then just add this. So then it's
complaining -- well, it was complaining about this case. So I know
that this is the case that I need to worry about.
>>:
[indiscernible].
>> Nada Amin: So then it tells me I need to show this post condition
holds for this case. Yeah. So it's saying this post condition here
with this squiggly doesn't -- it doesn't know that it's hold for this
case. So I need to help it. And the way I help it is by saying, well,
okay if you look at the TVAR case, if you look at actually the way it
was done in the has type function -- let me make this -- if you look
here, then you see that well actually in the substitution, what you see
is that it has these two cases so if X is equal to X prime then SST.
So that means that here I really have two cases to consider. If the ID
is equal to X as this, and now we see that Dafny is really confused
only about this case. And so now I can keep drilling and understand
why is this case tricky. Well, the reason it's tricky is that we're
actually using the -- so this is the case where we're doing the
substitution. And the reason it's tricky is that we're actually using
the fact that S is closed to do the context invariance.
>>: So like if you don't know the proof apriori, let's say you can
dig, but it's nothing you can gain --
>> Nada Amin: In some ways it's like -- so COC gives you the
interactive context and says this is the case you need to worry about.
Here is the same but you have the flexibility in choosing which order
you do the case because you know what you're doing a derivation on ->>: I know, but when I look at this proof and what you say there's
nothing that tells me that's what I have to do.
>> Nada Amin:
Yeah, so it's interactive.
You try it out.
>>:
But I really don't understand why you assert the equal equal is.
>> Nada Amin: Why it's there? Maybe it doesn't -- it's also just for
my understanding. I know that I'm in the case that is a variable, and
where the substitution is happening. So I know that I'm
substituting -- X is just -- T is just X and I'm doing the
substitution. So this whole thing just becomes S. So then the type of
this thing, which was T, we defined it to be T. We know this has to be
the same as S.
>>: You have like [indiscernible] or something that can give
intermediate status of why it's confused or something like that.
>> Nada Amin: There's a way but I haven't used debugging support much.
Okay. So now for preservation, it's really just using the substitution
lemma where it applies and the rest it applies automatically. That's
it. We're pretty much done. I'm defining what is a normal form. And
stuck is a normal form that isn't a value. And then I can show type
standards by using this progress and preservation. So that's the
generic part. So now what I want to show is how modular the proofs
are. What I did is I added some extensions. So I added boolean types.
Natural types. I also added isorecursive types, which are the
fold/unfold operation. I'll show you an example of this later. And
this is like -- Dafny doesn't have pragmas, I basically can comment
this in and out and what's interesting is that the model has to change.
Right? The model is changing I mean my values now include natural
numbers and these faults. And then so the model changes quite a bit.
And that's expected. I mean, after all, you're doing a new calculus.
But then what's really interesting is that for this case -- sorry. I'm
just going to scroll down. And just to show I'm actually using this,
so I have examples of boolean naturals and this fold thing. But what's
interesting is that the type [indiscernible] properties stay the same.
So the proofs that we had before are exactly the same. Nothing has
changed. And the reason is that if you look at the proofs, the only
interesting parts are for abstraction and variables and the application
parts really wasn't mentioned anywhere and so this new stuff is still
by induction on the congruent and everything just works. And I added
this isorecursive type because I actually wanted to find a case where
it doesn't work and so that I could show how I would extend the proof
but it still works. So I got -- yeah. So I think that's pretty cool.
I mean, if you look at how to achieve this in COC you really need to
have the insight beforehand to structure your proofs in the right way.
And just to show that things are actually working nicely. So if I add
the mistake, for example, if an S type, I change -- I change the if
statement so that -- if expression so it doesn't check that both
branches are the same.
Then hopefully I should get some error somewhere. So this tells you
when it's done. I haven't enabled the caching because it wasn't -there was some issues with it. But this should tell you when ->>:
Too fast and blow up the audience.
>> Nada Amin: Yes, so it says that it can't proof preservation
anymore. So you can begin on what the problem is I can say F is the
problem and T if. Well, here I know it's there. But I'm just going to
have a suspicion or I could even ask it is the problem with T full, for
example?
Or is it the problem somewhere else? And it tells me, yeah, the
problem is here. And since here I'm doing -- I'm kind of doing a case
analysis on the stepping functions. Yes, so here it's recomputing,
because when there's the purple line it's recomputing. So I know that
the problem is here, and I can look at the stepping function. And I
have the three cases here.
So it says it cannot show this. And if I add these three cases to tell
me which one is it's complaining about.
>>:
If you get --
>> Nada Amin:
>>:
Yeah.
So you need IDE support for this --
>> Nada Amin: Yes, otherwise it's hard. You can also -- it would be
too much -- the cycle would be too slow if you do it from the command
line.
>>: No, no, I meant
proof debugger. You
But it seems like -to sort of have some
simulate the event.
that each edit should be supported by some sort of
shouldn't be having to modify that sort of thing.
well, okay. It seems like there's an opportunity
notion of a proof debugger that's allowing you to
>>: Sort of like the -- a strategy where you can say basically it
shows you all the different places you have to consider, you could do
it here or in line the different data that you need to consider.
>> Nada Amin:
That's true.
>>: That's what I meant calling the thing. And another thing is so
should be probably some way incremental the way that it works because
it's easier proving everything when the bug is in the same place over
and over. So perhaps [indiscernible].
>>:
Turning off the caching.
>> Nada Amin: Turned off the caching. Because I wanted to make sure
it was signaling all the time. But anyway, that's one thing. So now
you know the problem is here. If you look at the stepping function is
going to step to the S branch and since we -- if we have something that
looks like this, I mean, this used to have type NAT because of the way
the wrong function, the wrong typing worked and now it has type two,
which is different. So you know there's a problem. So anyway this was
just to show some support. I mean, I guess now I have -- it's already
210. So I can discuss a little bit more -- yeah?
>>: At the end of it so and exclusivity side what's the
[indiscernible] what's like [indiscernible] do you use?
>> Nada Amin: So Dafny, for example, doesn't have high order
functions, which a big limitation, really, for especially in this kind
of setting. But usually you can represent -- so say in COC you would
use an environment for things, like a partial function environment.
And here you can use a map and things like this.
So otherwise in COC you have these relations that allow you to define
inductively what your evidence looks like, and in Dafny you can use
predicates for this, but it doesn't have quite the same expressivity,
especially in terms of like termination and co-induction because
co-inductive relations have certain properties and things.
But, yeah, I've been able to do quite some fancy systems in Dafny. So
one thing, for example, is doing logical relations, it's very hard to
do in COC because you have a lot of mutual inductions but in Dafny I
can just use a step index and it works quite well.
Any more questions? So that's it for the demo part. I thought this
example was nice because it shows that Dafny can do a lot of the
proving itself, and you can really focus on the interesting case. The
way I actually use it in practice is I worked top-down. So I start
with the theorem I want to prove and whenever a case gets complicated I
make up a lemma for this case and I keep going. And then later I
realize, oh, maybe this lemma is too generous, it's never going to hold
and I refine it and what's nice is that if the original proof works
with the more precise lemma, it still works. It's not like in COC
where you create a lemma, the exact form of the lemma really matters
for how you're going to use it in the proofs.
So what I mean here is that I use an example from my presentation,
yeah. So first I thought I needed this lemma which I guess you would
need to understand the calculus. But it's basically saying that if you
have -- it's basically the sub typing inversion. If you have two paths
and their types are sub types of each other and you can get something
from P, you should also be able to get something from whether this
should be a P prime here. You should get something from P prime and it
should be in the sub typing relation. And the problem then is that I
found it doesn't hold in my calculus which is strange because you would
expect this. Then I realized if I just add the additional rule P
reduces to P prime, all my proofs were still going through because in
every case Dafny managed to prove that P does reduce to P prime. And
then I was able to keep it as it is just by refining the lemma.
>>:
How do you -- [indiscernible].
>> Nada Amin: So I found that it didn't work, but just looking at it
and trying to prove it for a little bit and seeing in which case I got
stuck and then I came up with a counterexample.
Okay. So any questions about Dafny? So I thought I'd end up by
showing how I've been using Dafny in my own research, give a quick
introduction to what I've been going on with Martin Ordersky and others
at EPF.
>>: Could you just show publicly available data.
I mean, the proof of --
It's on your page.
>> Nada Amin: Yes it's on Get Hub Dafny sandbox.
things there, actually.
And there are other
>>:
Thank you.
>> Nada Amin: Okay. So what we're trying to do with this dependent
object type calculus is capture a core feature of Scala, which is path
dependent types. And the goal is really to have this core calculus be
what every other Scala type maps to. So we would only have this
path-dependent types, extract type members, and we would sync model,
Scala's mixture of nominal structural typing, but only refinement
types, but then Scala has [indiscernible] types, existential types, we
wouldn't treat a model directly in the calculus. We also don't want to
model inheritance. These would be expressed by translation to the
calculus. And just to give an example, just to give a brief overview
of the syntax, what we have is that the types are the most interesting
part. This is what we're trying to capture. So we start with a bottom
and top type. And then we have these refinement types, which allow you
to say that we're extending this type T with a set of declarations and
declarations can be values and methods as usual, but also types. And
if they're types you specify them by giving a lower bound type and an
upper bound type. And because types can have types as members, when
you have an object of a certain type, you should be able to refer to
these type members, and this is what is done with these path-dependent
types.
So P dot N means take the type member L from P and that's also a type.
>>: Make it concrete, make it like an object bit array and its element
of it.
>> Nada Amin: Yeah, to make it concrete you can have an animal and it
has some type mu which is upper bounded by fluid. So you would say
that the lower bound is bottom and the upper bound is food N dot. And
you could extend this animal with a cow and you would say that here the
meal is just grass. So it's upper bounded and lower bounded by grass.
And then you can reason about these things.
So if you have an animal you can't really feel anything if all you know
about it is an animal. If I could feed an animal, okay, well, meat,
then if it's a cow that wouldn't be so good. So and the reason this
works in the calculus is that whatever this type is, it has to be a
lower bound of A. Meal and you don't really know what A.meal is but you
can open it up. And since we're doing sub typing on the right with
meal, we open it up by looking at the lower bound. And here we have
bottom. So we cannot feed it anything.
On the other hand, if we have a cow, we can feed it grass, for the same
reason. Yeah, so this is to make it concrete, but really the point is
we just have these types of actions and refinement types. So it's
pretty minimal. Then we extend it with type intersections and unions
in the classical way to get a subtyping lattice. The goal was to
really have a minimal set of types and then try to see where we can go
from there.
One key motivation from Scala was that currently in Scala, it doesn't
have these classical intersection and union types when you compute the
greatest lower bound and least upper bound things have to be done in an
eager fashion and you can get into types that are actually approximated
by an infinite sequence. And in that, this would be solved by really
just -- I forgot this one.
So in dot this would be solved because you would just say, well, we
just want the least upper bound of C and D and this is just a type by
itself. So we're kind of delaying the problem to when we need to
expand this type and look at it. So the calculus itself is -- the
syntax is rather simple but in terms of judgment it gets a bit
complicated. Like you have the usual type of assignment, subtyping
wherefor this. You also have this expansion that allows you to
flatten, look out what is really the set of declarations and type,
because you could have nested refinements, refinements with
intersections, unions and things. And membership which allows you to
select a particular declaration from a term.
And so if we look at the example where we're looking at a function that
has an apply method and we're taking the union with another function
within apply method, then in practice what that means is that if we
type an application of this function, we need to take the -- this is
the type of the function that when we expand it we get this type for
the apply method. And so we see that the decomputation is done at the
time where you actually need to know -- it's not done at the time where
the function, when the type is defined, but at the time where the type
is used. So this was just to give you a flavor and for this concrete
example of animals, what happens with these bounds is that when we're
refining animal we still have to keep this -- we still have to use
these bounds from animal and from cow together. So the way we do it is
that for the -- for this refinement of animal here, we have this reads
that the lower bound is grass or bottom and upper bound is grass or
food and that just reduces to grass or grass. So that works fine here.
But if instead we just said, okay, mu can just be food with lower bound
food. Here we'd get that bound. So we'd get food to grass. And this
means in practice it means this type can never be instantiated because
when we create a type we check that the bounds are good.
>>:
Is this global?
>> Nada Amin: Yes. And one interesting aspect is that we don't really
have a separate class table for things. The denominality really comes
in through the path dependent types. Which means that here if I have
something that is a poodle, then I know that it's a pet because if it's
a poodle, I can open it up and see, okay, I really just need to compare
dog to pet and then I can compare pet to pet. So eventually every sub
typing rule on path dependent types if there's no structural aspect it
reaches a flexivity type part on the chain. Okay. Then I just wanted
to give a flavor of the kind of issues we have. So one example is that
we need to take path equality into account. Because here there's no
need to understand this code in detail but the gist of it is A.I.L
reduces to V.L. And V.L has this type that depends on V. And A.I.L
has this type A.I.X that depends on A.I. So somehow now we need to be
able to relate these two types but on a first approximation they're not
equal because A.I.X has a lower bound of bottom which means we can't
really compare it to V.X by opening it up.
But we know something more. We know that A.I reduces to V, so it it
works in this case but that means you're typing all that needs to take
path equality into account.
>>: The only node here because you write I equals B, being a
difference.
>> Nada Amin:
>>:
Exactly if here it was --
It's co-dependent.
>> Nada Amin: Well, it's -- it depends on what is in your store.
Yeah. I mean, this is only true because A.I reduces to B. If A.I was
reducing to B prime it wouldn't be true anymore.
>>:
Or couldn't [indiscernible] figure out what it reduced to.
>> Nada Amin: But that becomes an issue only when you have things in
the store. So it's really something that shows when you have
preservation.
And this is also related to the sub typing inversion, where you can -where you really -- where you really need to add close P reduces to P
prime and this lemma for it to actually work. And initially we also
had some very strange issues with well formness. One tricky aspect you
have intersections that are somewhat delayed because something looks
fine. So if you just look at the type over here down here it looks
fine by itself. And it's only when X.L is refined to be this type here
that you have a problem. And the problem is that if you look at the
red types by themselves, then you have that B refers to A and then here
A refers to B. So there's like a cyclic dependency between them and
somehow if you try to ensure -- depending on your well formness rules
you might get stuck in the most precise type and not in the previous
situation. So that's just to give a flavor. I mean, in summary what
we've been doing is really actually using Dafny to help guide the
design of the calculus also and figure out what do we really need for
preservation to hold. And we're also looking at alternatives using
logical relations and big steps semantics for this calculus. So that's
it. Any questions?
[applause]
>>: So have you represented some of the rules in this language in
Dafny already on slide 6.
>> Nada Amin: Yeah. Yeah, so I have the -- so this one is a very big
development actually. So it probably doesn't completely time out in
the ID. But it doesn't completely like -- there's some timeouts in the
ID when you run it. But the gist of it is you have this -- I'm going
to remove the other things. So the main thing is we have typing for
paths and the typing also takes the store in context and returns the
type for the path. And here I'm using what Mikel mentioned before I'm
using the predicate approach not the function approach. And I'm also
always using a step index so whenever I have any recursive call I'm
just decreasing the step index which allows me to really do mutual
induction proofs easily just based on that. And then -- and then we
have like all sorts of other things like well formed declarations and
everything. Well formed type. Then you can see, for example, this
membership and rule is not very constructive. It just says, well, I
mean it's using existentials a lot and things like this. So you can do
that sort of thing as well.
>>: So about the end, in COC a lot of times people will define things
like typing as data types. And then you can do induction on those data
types.
>> Nada Amin:
Yeah.
>>: But do you find that using this natural number is a better way to
do that induction or --
>> Nada Amin: So I missed a little bit being able to do inductive
evidence like kind of data types in the prop world in COC, but on the
other hand, in COC mentioned induction is quite tricky. Sure it does
some part of it automatically for you. But then you have to do a lot
of work to get it started, right? And here I have so many judgments
that using the step index is just so much easier. Like Dafny can
always say this is decreasing and then I can do my proofs. Of course,
the catch is that if I have a sort of unintended cyclic dependency
which means for some derivation it always goes to zero, then that's not
so great. But I need to watch out for this. But in general it's been
rather nice to do that.
Like just to show also one thing I didn't really do too much because
I'm using the step index I need to show things are monotonic. If you
increase the step index, you still get the same types. And so there's
these ghost lemmas that do this. And this I mean I didn't bother to
prove them. Like some of them I just assumed for now and keep going
with this. Okay. So I guess it's ->>: Question. I mean this is really awesome. I really like it.
for the moment I'm going to play the role of a grumpy COC person.
>>:
But
Just say Frenchman.
>>: You know, a criticism that such a person may raise is that type
systems are inherently these constructive things that you work with
that you get nice constructive proofs out of COC and you can interpret
COC theorems and the constructions and stuff. What can you say here?
>> Nada Amin: Yeah, that's -- I mean, well, hopefully I guess you're
getting to maybe having a verified core of Dafny. But, I don't know,
for me it's just really -- right now my concern is really, okay, I'm
doing this research calculus. Can I -- how do I get some guidance on
proving it's sound when there's so many hairy issues. And I find that
doing things in Dafny allows me to focus on the big picture. I mean,
eventually maybe it's not convincing to everyone. But for me it
focuses on the big picture. I can really -- I don't need to do this
low level manipulation to get the exact proof term that I need for
something. But I mean under the hood I think if Z 3 is sound, then
things are fine, right?
>>:
Question.
>> Nada Amin:
One of the classical constructor stuff.
Yeah.
>>: I guess. I guess maybe one way I might look at it is to say,
look, there's a community of people doing time proofs. There's a
community of people these days who do meta theory in COC. And maybe
this is sort of somewhere in the middle you don't necessarily get the
tiny TCP but you may get the COC. But certainly it's way better than a
hand proof. Maybe we don't need like micro-TCP [indiscernible].
>> Nada Amin: And I think especially for teaching, Dafny has a lot of
potential, because the way it does induction is very natural. So even
just learning these concepts, it would be much easier in Dafny than in
COC where you have to learn the machinery and the stepping curve is
really high. Dafny uses some concepts that you already kind of
understand which is contracts. And bootstraps from there to do more
serious proving.
>>: Is there any way to get Dafny [indiscernible] it's generally in
these proofs where you have the empty code basis. But it's excluded.
>> Nada Amin:
>>:
I don't know.
Black box.
>> Nada Amin: I mean, one thing you can do is you can also -- if you
really want to -- so it depends why you're doing the proof, right? If
you really want to -- if you're doing it as a beginner student trying
to understand progress it's not so helpful it's just saying, well,
that's done. So one thing you can do is really do say here induction
false, and then yourself try to do the steps manually. And I mean in
this case it wouldn't be so hard. It would still help you with other
aspects. But there's a way to try to get more insights.
>>: One way to think about it is that if this is saving human time to
do the proofs in the first place, then if you are really wondering
about -- is it the sound proof, then one could imagine that one would
take the proofs that Z3 constructs, map them back to -- first of all,
generate those proofs, and then map that back to the GUI level and then
to the Dafny level. That would be a large project to do.
But I mean some people like doing that.
a lot of people, could be nothing.
And if it would mean a lot to
>>: I guess I just was wondering if there was some way to get the
proof in a format that's verifiable by something that's not verifiable.
>>:
Right.
>>:
Z-3.
>>: But it's a notion of what a proof is then it needs to be
manipulated and fed to something else that would then -- you want
independent verification. And so it's possible, but it's a big
project. Because Z-3 still does its proofs very big steps. It's as I
think ->>:
Compared to some other things.
>>:
Right.
>>:
If somebody could --
>>:
Compared to what you're using as the checker.
>>: And one could also mention that such a project, such a project
would be a very large one. You started with something that like in
these examples you use functions and data types. Maybe there's a more
direct translation of these proofs and the input to let's say Isabel or
something or would call for that matter.
>>:
Nothing's there.
>>: But I guess you didn't show it here, the calc statement.
Sometimes when you write the proofs yourselves, instead of having just
the certs and calls out to lemmas, you can use verified calculations.
And those are like human default.
>> Nada Amin: Yeah, there was just one trick like regarding the
capture avoiding substitution. So you can do a renaming like here.
Well, this is for like type substitution, but it's the same thing. But
the problem then is that the decreasing cloud is a bit -- you need to
decrease on the size of your data type instead of the actual structural
look of the data type. But you can also do this in Dafny quite easily
by defining your own decreasing measures and things. Okay.
>>:
Deeply impressive.
>>: So now she's here until the end of the week. So if you want to
pick parts of her brain, let me know, or if you want to show her the
related things, whatever that might be.
[applause]
>> Nada Amin: Thank you.
Download