Tip:
Highlight text to annotate it
X
. Alright, without much further ado, let's get started with programming in ML. what I
really hope you'll do, as we start doing this, is let go of any programming or any
programming language that you already know. For now, treat M L as this totally
new thing. If you prefer, don't even call it programming. We'll have plenty of time
later to compare and contrast what we're going to do in ML to things that you
already know. And, and I really think that if, right know, you try to take each thing
that I write down. And say, oh. That's kind of like this thing I know in Java, or
in Python, or in whatever. it's going to confuse you, and, and make things really
difficult. So it may seem like I'm going really slowly. But focus on than the words
and the terms and how we're thinking about stuff, rather than trying to guess what
the answers going to be as we go. Alright? So I'll usually have things open for us in
advance. But since this is the first time I'm showing this to you what I'm going to
do now is open the Emax editor. So this is what it looks like right after I open it.
Your colors may be different. I've chosen these colors because I think they'll
record better. And in fact I'm going to switch the size here as well. So that
it'll be easier for you to see. Now I'm just going to open any file I want. I'll
usually have this pre-done, but again I'm just, I hit control X control F and now
I'm just passing in a pathname. This file doesn't actually exist yet. First dot SML.
We're always going to use SML for our file extensions. Hit return and now I have this
blank file here. By the way, another simple thing you can do is if you create
the file ahead of time, you can literally take your mouse, at least under Windows,
and drag the file onto EMACS and it will open. So here I am, in a blank file, and
the first thing I'll do is write a comment. So this is a comment. this is our
program so comments like in every programming language I'm familiar with are
just things that are ignored by anything except humans and in standard ML we start
our comments with a round parenthesis and then a star and we end them with a star
and then a round parenthesis and yes you can nest comments inside of each other so
that's just a comment we haven't written any program yet. let's write one line
program, val x equals 34. This program is going to create a variable. And is going
to have that variable hold 34 and because 34 is something of type int, short for the
english word integer, x will be a variable of type int. Okay so what we see here is
we are creating a new variable using the val keyword. So val is a special word in
the language that says, I'm about to introduce a variable. X is the variable
name we chose, we could've chosen any you know s thing there like y or phu or hello
or Dan. Equals is part of the syntax of declaring a variable and then here between
the equals and the semicolon to end it I've put an expression and the simplest
kind of expression we have is just an integer constant. So let me do a second
one. Let's create a variable y that has value seventeen. Alright? Now I'm going to
save with control x control s and now this is a program. I didn't need a main. I
didn't need a class. I didn't need a method. For today, for this video, a
program is just a sequence of these variable bindings. So each of these is a
binding. We have a sequence of them and that's our program. If I want to run this
program, I'm going to use the standard ML REPL, the read eval print loop. We'll talk
more about that in a couple of videos. But for now, let me just give you the basics
of how you run this program. So I'mm going to type control c control s, then hit
return and that brings up this other window, where I can now say use, and then
first dot sml. So the name of my file inside of quotation marks to make it a
string, this function although think of it as a command use then a semicolon and then
hit return. And sure enough I get a message that it's opening that file and it
tells me some things, it says that it's created a value x, a variable x, that
contains 34 and has type ent, a variable y that contains seventeen and has type ent
and then this last line you'll always see this is actually the result of running use
and you're free to ignore it. So, I can now continue. I could add more things to
my file. But I can also just use this prompt to see things. So if I type X semi
colon, it'll say, oh, that's 34, it has type ent. If I said X plus seven semi
colon. It would say, oh, that's 41, and it has type ent. If I say X plus seven and
forget the semi colon, it'll wait for me to continue some longer command. And so I
can end it with semi colon. Or I could have split things onto multiple lines, and
maybe added y to that, and then semicolon. And that would be 58, and so on. we'll
have more to say about the ripple in a bit. But for this video, what I want to do
is just go back and continue writing our program. and understand the exact meaning
of what it means to have a sequence of bindings. So, the nice thing about this
sequence is that you can use earlier things in the sequence. So if I have X
plus Y plus Y plus two. Now what will happen is when I go to create the variable
binding for z, it will be able to use the earlier bindings. Now an obvious question
would be can you use later bindings. And the answer is you can not. And that might
seem very strange or unusual but it has certain advantages that we'll talk about
in a couple videos. But the rule, every programming language has different rules,
is that you can only use the earlier bindings. And the reason is. That we can
actually keep track of exactly what our program means as we go along. So I'm going
to do this in comments but this is exactly what the implementation of the language is
doing when it sees all this code. So initially we don't have anything. Now it
turns out we (want some) predefined functions and variables but we haven't
defined anything yet. And now after. We create this available binding X. What we
have, is what we have, I'll call it dynamic environment. It's the environment
you have when you're running the p rogram, and in that environment, let's say X holds
34. Alright? And then after the next one, we'll have a dynamic environment.
Environment where X holds 34 and y holds seventeen. And that's why when we get to
this third one. we still have X holds 34 and Y holds seventeen, and so what happens
is we get to this expression and we evaluate it in the current dynamic
environment. So when you have an addition expression you go and evaluate the two sub
pieces. So in this addition expression, the two sub pieces. When you get a
variable, you look it up in the environment. So we look up X. We get 34.
We look up Y. We get seventeen. Together that's 51. Over here, we'll end up looking
up Y again. That will give us seventeen. Add two more. That's nineteen, and if my
math is correct, we'll get what? About 70 here. so Z will in this environment, now
map to 70. And this is how we continue as we evaluate our program. So if next we had
Z plus one. Then I'm just going to paste this down. We'd have everything we did
have in our environment. And now W holds 71. Now there's something that happens
before any of this, and that is that our entire program, our file, our sequence of
bindings, is type checked. Ml is a language with a type system. And if your
program makes inconsistent assumptions about, what's an int? Or, or, or tries to
use a variable that's not defined. You get an error before you ever try to run the
program. And that it taken care of by what I'll call the static environment. Even
though I'm showing this to you second. This all happens before the program is
ever evaluated. Before it's ever run. So what actually happened is the
implementation first went through this whole program and said, oh, because 34 is
an int, I know that, that's built into the language, X will have type int. It will
hold something of type int. And similarly, as I go back through this sequence, I say,
oh, well, X has type int and Y has type int. Alright? And here now this is more
interesting, the only reason that z gets to also have type int. . Is bec ause, when
I looked at this expression. When the type checker looked at this expression. It
said, well, addition has type int, if both the sub expressions on the two sides have
type int. Similarly, this addition can have type int if x and y have type int.
And when you get a variable, you type check it by looking it up in the static
environment. So the static environment acts a lot like the dynamic environment,
except it just deals with what's an int or what's defined or what's not, and so it
doesn't actually run the program, alright? So what really happens when you take this
file is first everything type checks. Then if that passes, everything runs. Now it
may not look that way, if I flip over to my repal here, and I'm always going to
restart before I show you something after I have changed the file, it looks like it
just figured out altogether that x is a 34 it has type n y is seventeen is type n. I
really like to think of the type checking as coming before the evaluation. All
right. Let me show you a couple more kinds of expressions, and then we'll wrap up
this segment. first let me show you a conditional. So here, let me finish
writing it out and then I'll walk you through what's going on here. So I'm just
creating another variable, this one's called abs of z. And it says if z is less
than zero, then zero minus z else z. And as you might imagine, the way an if
expression is evaluated is different than addition. It doesn't go in an evaluate all
the sub expressions It, it first looks at this first sub expression, z less than
zero. It looks up Z in the dynamic environment, gets 70. Takes zero, asks
less than, that's false. so as a result, it ignores this expression between ven and
els, never evaluates it. And instead, evaluates just the things after the els,
gets a result. In this case, 70. And so, the result of the entire thing. This if
will be 70 and will end up therefor putting the result as the value for abs
sub Z which is shorthand for the absolute value of Z. So in fact in our dynamic
environment here, we' ll have everything we had before as, and then that abs sub Z
maps to 70. As for the type checking, the way we type check in if, then, else, is
the thing between the if and the then has to be something of type bool. And indeed,
less then, returns a bool, short for Boolean, given two integer arguments. And
then these two branches can have any type they want, but they have to have the same
type. In this case, fortunately, they both have type int. And so the result of the
entire if expression is type int which is why x of z in our static environment,
indeed has type it. As does everything else we've added to our static environment
in this first file. And by the way, you know this is a real programming language
with lots of built in features like less than and plus and minus. we didn't
actually have to do it that way, there's a function defined for us called ABS which
takes an int and returns it to absolute value. This is the first time I'm showing
you calling a function you might be used to something like this and you can write
it that way, but the parenthesis don't actually matter, you can leave them out
and this would have done the same thing. Okay, so that's our first program. Let me
now get rid of this and just give you a little more sense of how the slides will
work after I show you the code. So here's basically the program we just wrote. I
like to include it in the slides so if you're looking through the slides you
don't have to flip back and forth. But we already saw all this. What we focus on
here were variable bindings, and in general the way we have a variable
binding, is we are at val, the name of the variable, the equal sign, an expression
which I'm representing here in the middle of the slide with e, and then a semicolon.
Now what I've just described is the syntax. Syntax is how you write something
down. I haven't said what it means. That we talked about with the code and I have
it here on the last slide of this little segment. And that's the semantics. So
syntax is how you write something. Semantics is what that something means.
And we're dividing our semantics into type checking. Which is what we do before the
program runs to make sure there's nothing inconsistent. You don't use a variable
that's not defined. You don't try to add something that's not a number. That sort
of thing. And then evaluation which is what happens when the program runs. And
for these variables bindings which is all I showed you here. You type check the
expression, that E after the equals, and use that to extend the static environment.
When you evaluate the expression, that ends up extending the dynamic environment.
So that's this meaning of variable bindings, but it seems clear that the
meaning is going to depend on what kind of expression we have. So for each kind of
expression variables, additions, conditionals, less than, they're going to
have they're own syntax, type checking rules and evaluation rules. And to go
through those we can go to the next video.