we're gonna learn the truth about a lot of what we've been doing.
sugar in our ML programs than we even realized.
that in ML, as a result, every function takes exactly one argument.
Not zero, not two, not three.
And this is a very flexible, elegant way to design your language.
I need to extend our definition of pattern-matching a little bit.
bindings, and that's because we needed some way to access the values.
get the underlying pieces out, was with pattern-matching.
it turns out that pattern-matching also works for each-of types.
records, it works for tuples as well.
which we'll use in increasingly good style as we go along.
So here's a new kind of pattern.
except between the commas we have variables.
against a tuple value, it will bind.
up to xn being matched against the last component of the tuple.
to the number of variables in your pattern.
You're not allowed to mess that up.
that matches a record value that has those same field names.
As usual the order of the field names doesn't matter.
the value in the f1 field, x2 in the f2 field, and so on, all right?
So that was a little abstract, let's see some examples.
we'll get to the better style in just a second.
was an integer, and I just want a little function to add those three numbers up.
that took in some argument, call it triple.
matches against tuples that have three parts.
and since I add them together, those pieces must all have type int.
in tuples holding three integer things, and the return type is int, all right?
And similarly here's a function full_name.
It takes a record where you have fields first, middle, and last.
Here I'm concatenating them all.
in fact, the three fields are going to have to hold data of type string.
and binding to z whatever is in the last field.
we're just doing it on each-of types, instead of one of types.
now let me tell you another feature that gives us a better way to write this down.
I told you that val-bindings were written by val variable name equals expression.
And it turns out that's true, but it's not the whole truth.
against the entire result of evaluating the expression e.
then it will match against the expression e as well, and extract the various pieces.
you can even only get some of the pieces out that you need.
is one of the constructors of a data type binding.
a case expression with only one branch.
data types you really want all the different branches.
checker makes sure you cover all the possibilities.
Okay, so here's how our examples would look now.
which is bad style, let's use a let expression instead.
what I'm gonna do is pattern match it with this val binding here.
So that will indeed evaluate triple.
z to the third piece.
expression, and I can add them together.
because otherwise the rest of this expression wouldn't type check.
exactly the fields first, middle, and last, all holding strings.
So this is actually quite nice style, but I'm gonna show you something even better.
I have to tell you one more truth about ML.
It turns out that a function argument can be a pattern and not just a variable.
it turns out what goes right there is actually a pattern.
if it's a pattern, we'll go ahead and extract pieces of the argument.
So now what I have are these beautiful functions.
to the third piece, and then the body can do whatever it wants, add them together.
will have to be passed something that can match against this pattern.
and last all hold values of type string, okay?
records, we can write this much more concise, elegant, simple code.
this pound character on your keyboard, Shift+3 for me.
cuz that's what we're working on.
the arguments to your functions or any other variables that you're using, okay?
show you something really interesting.
sum_triple we've been working on.
we put the pattern directly in the function argument.
one is really syntactic sugar if you like, for another.
returns an int, and that's the type of all three versions of sum_triple you see here.
middle, string and return a string.
you get a 12 if you do it that way, and I'll try one other here.
You get a 12 if you do it this way.
So in all cases take a triple, return an int.
let's look at this third possibility here, this sum_triple.
That looks to me like a function that takes three arguments.
how can ML tell which of it I'm trying to do?
instead of passing in three arguments, a 3, a 4, and a 5, okay?
So let me put this another way.
it does it via pattern-matching, as I've just taught you in this segment.
takes three arguments, x, y, and z, and adds them together and returns it.
the bottom half, you're seeing something I don't, because they're exactly the same.
we've actually been using pattern-matching all along, I just didn't tell you.
So here is the big truth.
just functions that take one argument that is a tuple.
that you get the different pieces of that tuple out.
This is extremely elegant and flexible, and I'm not gonna kid you.
a three argument function, a four argument function, and so on.
is that that's just syntactic sugar.
pattern matching to get the pieces out, and this is actually a useful thing to do.
Here is a very simple program to rotate the pieces of a tuple.
(x,y,z) = (y,z,x), all right?
and I actually spell it correctly, I get (4,5,3), all right?
12 because the order doesn't matter when you're summing things up.
This is something you can't do in a lot of programming languages.
I can immediately take that thing and pass it to another function.
cuz it turns out if you have a triple, two left rotations is one right rotation.
easier to take the results of one function and pass them directly to another.
So now we know the truth about ML functions.
to have a special concept of multi-argument functions.