Placeholder Image

Subtitles section Play video

  • PROFESSOR: Well, yesterday we learned a bit about symbolic

  • manipulation, and we wrote a rather stylized program to

  • implement a pile of calculus rule from the calculus book.

  • Here on the transparencies, we see a bunch of calculus rules

  • from such a book.

  • And, of course, what we did is sort of translate these rules

  • into the language of the computer.

  • But, of course, that's a sort of funny strategy.

  • Why should we have to translate these rules into the

  • language of the computer?

  • And what do I really mean by that?

  • These are--the program we wrote

  • yesterday was very stylized.

  • It was a conditional, a dispatch on the type of the

  • expression as observed by the rules.

  • What we see here are rules that say if the object being

  • the derivative is being taken of, if that expression is a

  • constant, then do one thing.

  • If it's a variable, do another thing.

  • If it's a product of a constant times a variable, do

  • something and so on.

  • There's sort of a dispatch there on a type.

  • Well, since it has such a stylized behavior and

  • structure, is there some other way of writing this program

  • that's more clear?

  • Well, what's a rule, first of all?

  • What are these rules?

  • Let's think about that.

  • Rules have parts.

  • If you look at these rules in detail, what you see, for

  • example, is the rule has a left-hand side and a

  • right-hand side.

  • Each of these rules has a left-hand side and the

  • right-hand side.

  • The left-hand side is somehow compared with the expression

  • you're trying to take the derivative of.

  • The right-hand side is the replacement for that

  • expression.

  • So all rules on this page are something like this.

  • I have patterns, and somehow, I have to produce, given a

  • pattern, a skeleton.

  • This is a rule.

  • A pattern is something that matches, and a skeleton is

  • something you substitute into in order to get a new

  • expression.

  • So what that means is that the pattern is matched against the

  • expression, which is the source expression.

  • And the result of the application of the rule is to

  • produce a new expression, which I'll call a target, by

  • instantiation of a skeleton.

  • That's called instantiation.

  • So that is the process by which

  • these rules are described.

  • What I'd like to do today is build a language and a means

  • of interpreting that language, a means of executing that

  • language, where that language allows us to directly express

  • these rules.

  • And what we're going to do is instead of bringing the rules

  • to the level of the computer by writing a program that is

  • those rules in the computer's language--

  • at the moment, in a Lisp--

  • we're going to bring the computer to the level of us by

  • writing a way by which the computer can understand rules

  • of this sort.

  • This is slightly emphasizing the idea that we had last time

  • that we're trying to make a solution to a class of

  • problems rather than a particular one.

  • The problem is if I want to write rules for a different

  • piece of mathematics, say, to simple algebraic

  • simplification or something like that, or manipulation of

  • trigonometric functions, I would have to write a

  • different program in using yesterday's method.

  • Whereas I would like to encapsulate all of the things

  • that are common to both of those programs, meaning the

  • idea of matching, instantiation, the control

  • structure, which turns out to be very complicated for such a

  • thing, I'd like to encapsulate that separately from the rules

  • themselves.

  • So let's look at, first of all, a representation.

  • I'd like to use the overhead here.

  • I'd like-- there it is.

  • I'd like to look at a representation of the rules of

  • calculus for derivatives in a sort of simple language that

  • I'm writing right here.

  • Now, I'm going to avoid--I'm going to avoid

  • worrying about syntax.

  • We can easily pretty this, and I'm not interested in making--

  • this is indeed ugly.

  • This doesn't look like the beautiful text set dx by dt or

  • something that I'd like to write,

  • but that's not essential.

  • That's sort of an accidental phenomenon.

  • Here, we're just worrying about the fact that the

  • structure of the rules is that there is a left-hand side

  • here, represents the thing I want to match against the

  • derivative expression.

  • This is the representation I'm going to say for the

  • derivative of a constant, which we will call c with

  • respect to the variable we will call v. And what we will

  • get on the right-hand side is 0.

  • So this represents a rule.

  • The next rule will be the derivative of a variable,

  • which we will call v with respect to the same variable

  • v, and we get a 1.

  • However, if we have the derivative of a variable

  • called u with respect to a different variables

  • v, we will get 0.

  • I just want you look at these rules a little bit and see how

  • they fit together.

  • For example, over here, we're going to have the derivative

  • of the sum of an expression called x1 and an

  • expression called x2.

  • These things that begin with question marks are called

  • pattern variables in the language that we're inventing,

  • and you see we're just making it up, so pattern variables

  • for matching.

  • And so in this--

  • here we have the derivative of the sum of the expression

  • which we will call x1.

  • And the expression we will call x2 with respect to the

  • variable we call v will be-- here is the right-hand side:

  • the sum of the derivative of that expression x1 with

  • respect to v-- the right-hand side is the skeleton--

  • and the derivative of x2 with respect to v. Colons here will

  • stand for substitution objects.

  • They're--we'll call them skeleton evaluations.

  • So let me put up here on the blackboard for a second some

  • syntax so we'll know what's going on

  • for this rule language.

  • First of all, we're going to have to worry about the

  • pattern matching.

  • We're going to have things like a symbol like foo matches

  • exactly itself.

  • The expression f of a and b will be used to match any list

  • whose first element is f, whose second element is a, and

  • whose third element is b.

  • Also, another thing we might have in a pattern is that--

  • a question mark with some variable like x.

  • And what that means, it says matches anything, which we

  • will call x.

  • Question mark c x will match only constants.

  • So this is something which matches a constant colon x.

  • And question mark v x will match a variable,

  • which we call x.

  • This is sort of the language we're making up now.

  • If I match two things against each other, then they are

  • compared element by element.

  • But elements in the pattern may contain these syntactic

  • variables, pattern variables, which will be used to match

  • arbitrary objects.

  • And we'll get that object as the value in the name x here,

  • for example.

  • Now, when we make skeletons for instantiation.

  • Well, then we have things like this.

  • foo, a symbol, instantiates to itself.

  • Something which is a list like f of a and b,

  • instantiates to--

  • well, f instantiates to a 3-list, a list of three

  • elements, okay, which are the results of instantiating each

  • of f, a, and b.

  • And x well--we instantiate to the value of x as in the

  • matched pattern.

  • So going back to the overhead here, we see--we see that all

  • of those kinds of objects, we see here a pattern variable

  • which matches a constant, a pattern variable which matches

  • a variable, a pattern variable which will match anything.

  • And if we have two instances of the same name, like this is

  • the derivative of the expression which is a variable

  • only whose name will be v with respect to some arbitrary

  • expression which we will call v, since this v appears twice,

  • we're going to want that to mean they have to be the same.

  • The only consistent match is that those are the same.

  • So here, we're making up a language.

  • And in fact, that's a very nice thing to be doing.

  • It's so much fun to make up a language.

  • And you do this all the time.

  • And the really most powerful design things you ever do are

  • sort of making up a language to solve problems like this.

  • Now, here we go back here and look at some of these rules.

  • Well, there's a whole set of them.

  • I mean, there's one for addition and one for

  • multiplication, just like we had before.

  • The derivative of the product of x1 and x2 with respect to v

  • is the sum of the product of x1 and the derivative x2 with

  • respect to v and the product of the

  • derivative of x1 and x2.

  • And here we have exponentiation.

  • And, of course, we run off the end down here.

  • We get as many as we like.

  • But the whole thing over here, I'm giving this--this list of

  • rules the name "derivative rules."

  • What would we do with such a thing once we have it?

  • Well, one of the nicest ideas, first of all, is I'm going to

  • write for you, and we're going to play with it all day.

  • What I'm going to write for you is a program called

  • simplifier, the general-purpose simplifier.

  • And we're going to say something like define dsimp to

  • be a simplifier of the derivative rules.

  • And what simplifier is going to do is, given a set of

  • rules, it will produce for me a procedure which will

  • simplify expressions containing the things that are

  • referred to by these rules.

  • So here will be a procedure constructed for your purposes

  • to simplify things with derivatives in them such that,

  • after that, if we're typing at some list system, and we get a

  • prompt, and we say dsimp, for example, of the derivative of

  • the sum of x and y with respect to x--

  • note the quote here because I'm talking about the

  • expression which is the derivative--

  • then I will get back as a result plus 1 0.

  • Because the derivative of x plus y is the derivative of x

  • plus derivative y.

  • The derivative of x with respect to x is 1.

  • The derivative of y with respect to x is 0.

  • It's not what we're going to get.

  • I haven't put any simplification at that level--

  • algebraic simplification--

  • yet.

  • Of course, once we have such a thing, then we can--then we

  • can look at other rules.

  • So, for example, we can, if we go to the slide, OK?

  • Here, for example, are other rules that we might have,

  • algebraic manipulation rules, ones that would be used for

  • simplifying algebraic expressions.

  • For example, just looking at some of these, the left-hand

  • side says any operator applied to a constant e1 and a

  • constant e2 is the result of evaluating that operator on

  • the constants e1 and e2.

  • Or an operator, applied to e1, any expression e1 and a

  • constant e2, is going to move the constant forward.

  • So that'll turn into the operator with

  • e2 followed by e1.

  • Why I did that, I don't know.

  • It wouldn't work if I had division, for example.

  • So there's a bug in the rules, if you like.

  • So the sum of 0 and e is e.

  • The product of 1 and any expression e is e.

  • The product of 0 and any expression e is 0.

  • Just looking at some more of these rules, we could have

  • arbitrarily complicated ones.

  • We could have things like the product of the constant e1 and

  • any constant e2 with e3 is the result of multiplying the

  • result of--multiplying now the constants e1 and e2 together

  • and putting e3 there.

  • So it says combine the constants that I had, which

  • was if I had a product of e1 and e2 and e3 just multiply--I

  • mean and e1 and e2 are both constants, multiply them.

  • And you can make up the rules as you like.

  • There are lots of them here.

  • There are things as complicated, for example, as--

  • oh, I suppose down here some distributive law, you see.

  • The product of any object c and the sum of d and e gives

  • the result as the same as the sum of the product of c and d

  • and the product of c and e.

  • Now, what exactly these rules are doesn't very

  • much interest me.

  • We're going to be writing the language that will allow us to

  • interpret these rules so that we can, in fact, make up

  • whatever rules we like, another whole language of

  • programming.

  • Well, let's see.

  • I haven't told you how we're going to do this.

  • And, of course, for a while, we're going to work on that.

  • But there's a real question of what is--what am I going to do

  • at all at a large scale?

  • How do these rules work?

  • How is the simplifier program going to manipulate these

  • rules with your expression to produce a reasonable answer?

  • Well, first, I'd like to think about these rules as being

  • some sort of deck of them.

  • So here I have a whole bunch of rules, right?

  • Each rule--

  • here's a rule--

  • has a pattern and a skeleton.

  • I'm trying to make up a control structure for this.

  • Now, what I have is a matcher, and I have something which is

  • an instantiater.

  • And I'm going to pass from the matcher to the instantiater

  • some set of meaning for the pattern variables, a

  • dictionary, I'll call it.

  • A dictionary, which will say x was matched against the

  • following subexpression and y was matched against another

  • following subexpression.

  • And from the instantiater, I will be making expressions,

  • and they will go into the matcher.

  • They will be expressions.

  • And the patterns of the rules will be fed into the matcher,

  • and the skeletons from the same rule will be fed into the

  • instantiater.

  • Now, this is a little complicated because when you

  • have something like an algebraic expression, where

  • someth--the rules are intended to be able to allow you to

  • substitute equal for equal.

  • These are equal transformation rules.

  • So all subexpressions of the expression

  • should be looked at.

  • You give it an expression, this thing, and the rules

  • should be cycled around.

  • First of all, for every subexpression of the

  • expression you feed in, all of the rules must be

  • tried and looked at.

  • And if any rule matches, then this process occurs.

  • The dictionary--the dictionary is to have some values in it.

  • The instantiater makes a new expression, which is basically

  • replaces that part of the expression that was matched in

  • your original expression.

  • And then, then, of course, we're going to recheck that,

  • going to go around these rules again, seeing if that could be

  • simplified further.

  • And then, then we're going to do that for every

  • subexpression until the thing no longer changes.

  • You can think of this as sort of an organic process.

  • You've got some sort of stew, right?

  • You've got bacteria or something, or enzymes in some,

  • in some gooey mess.

  • And there's these--and these enzymes change things.

  • They attach to your expression, change it, and

  • then they go away.

  • And they have to match.

  • The key-in-lock phenomenon.

  • They match, they change it, they go away.

  • You can imagine it as a parallel process of some sort.

  • So you stick an expression into this mess, and after a

  • while, you take it out, and it's been simplified.

  • And it just keeps changing until it no

  • longer can be changed.

  • But these enzymes can attach to any part of the, of the

  • expression.

  • OK, at this point, I'd like to stop and ask for questions.

  • Yes.

  • AUDIENCE: This implies that the matching program and the

  • instantiation program are separate

  • programs; is that right?

  • Or is that-- they are.

  • PROFESSOR: They're separate little pieces.

  • They fit together in a larger structure.

  • AUDIENCE: So I'm going through and matching and passing the

  • information about what I matched to an instantiater,

  • which makes the changes.

  • And then I pass that back to the matcher?

  • PROFESSOR: It won't make a change.

  • It will make a new expression, which has, which has

  • substituted the values of the pattern variable that were

  • matched on the left-hand side for the variables that are

  • mentioned, the skeleton variables or evaluation

  • variables or whatever I called them, on the right-hand side.

  • AUDIENCE: And then that's passed back into the matcher?

  • PROFESSOR: Then this is going to go around again.

  • This is going to go through this mess until

  • it no longer changes.

  • AUDIENCE: And it seems that there would be a danger of

  • getting into a recursive loop.

  • PROFESSOR: Yes.

  • Yes, if you do not write your rules nicely, you are--

  • indeed, in any programming language you invent, if it's

  • sufficiently powerful to do anything, you can write

  • programs that will go into infinite loops.

  • And indeed, writing a program for doing algebraic

  • manipulation for long will produce infinite loops.

  • Go ahead.

  • AUDIENCE: Some language designers feel that this

  • feature is so important that it should become part of the

  • basic language, for example, scheme in this case.

  • What are your thoughts on--

  • PROFESSOR: Which language feature?

  • AUDIENCE: The pairs matching.

  • It's all application of such rules should be--

  • PROFESSOR: Oh, you mean like Prolog?

  • AUDIENCE: Like Prolog, but it becomes a more general--

  • PROFESSOR: It's possible.

  • OK, I think my feeling about that is that I would like to

  • teach you how to do it so you don't depend upon some

  • language designer.

  • AUDIENCE: OK.

  • PROFESSOR: You make it yourself.

  • You can roll your own.

  • Thank you.

  • Well, let's see.

  • Now we have to tell you how it works.

  • It conveniently breaks up into various pieces.

  • I'd like to look now at the matcher.

  • The matcher has the following basic structure.

  • It's a box that takes as its input an expression and a

  • pattern, and it turns out a dictionary.

  • A dictionary, remember, is a mapping of pattern variables

  • to the values that were found by matching, and it puts out

  • another dictionary, which is the result of augmenting this

  • dictionary by what was found in matching this expression

  • against this pattern.

  • So that's the matcher.

  • Now, this is a rather complicated program, and we

  • can look at it on the overhead over here and see, ha, ha,

  • it's very complicated.

  • I just want you to look at the shape of it.

  • It's too complicated to look at except in pieces.

  • However, it's a fairly large, complicated program with a lot

  • of sort of indented structure.

  • At the largest scale--

  • you don't try to read those characters, but at the largest

  • scale, you see that there is a case analysis, which is all

  • these cases lined up.

  • What we're now going to do is look at this in a bit more

  • detail, attempting to understand how it works.

  • Let's go now to the first slide, showing some of the

  • structure of the matcher at a large scale.

  • And we see that the matcher, the matcher takes as its input

  • a pattern, an expression, and a dictionary.

  • And there is a case analysis here, which is made out of

  • several cases, some of which have been left out over here,

  • and the general case, which I'd like you to see.

  • Let's consider this general case.

  • It's a very important pattern.

  • The problem is that we have to examine two trees

  • simultaneously.

  • One of the trees is the tree of the expression, and the

  • other is the tree of the pattern.

  • We have to compare them with each other so that the

  • subexpressions of the expression are matched against

  • subexpressions of the pattern.

  • Looking at that in a bit more detail, suppose I had a

  • pattern, a pattern, which was the sum of the product of a

  • thing which we will call x and a thing which we will call y,

  • and the sum of that, and the same thing we call y.

  • So we're looking for a sum of a product whose second--whose

  • second argument is the same as the second

  • argument of the sum.

  • That's a thing you might be looking for.

  • Well, that, as a pattern, looks like this.

  • There is a tree, which consists of a sum, and a

  • product with a pattern variable question mark x and

  • question mark y, the other pattern variable, and question

  • mark y, just looking at the same, just writing down the

  • list structure in a different way.

  • Now, suppose we were matching that against an expression

  • which matches it, the sum of, say, the product of 3 and x

  • and, say, x.

  • That's another tree.

  • It's the sum of the product of 3 and x and of x.

  • So what I want to do is traverse these two trees

  • simultaneously.

  • And what I'd like to do is walk them like this.

  • I'm going to say are these the same?

  • This is a complicated object.

  • Let's look at the left branches.

  • Well, that could be the car.

  • How does that look?

  • Oh yes, the plus looks just fine.

  • But the next thing here is a complicated thing.

  • Let's look at that.

  • Oh yes, that's pretty fine, too.

  • They're both asterisks.

  • Now, whoops!

  • My pattern variable, it matches against the 3.

  • Remember, x equals 3 now.

  • That's in my dictionary, and the dictionary's going to

  • follow along with me: x equals three.

  • Ah yes, x equals 3 and y equals x, different x.

  • The pattern x is the expression x, the pattern y.

  • Oh yes, the pattern variable y, I've already

  • got a value for it.

  • It's x.

  • Is this an x?

  • Oh yeah, sure it is.

  • That's fine.

  • Yep, done.

  • I now have a dictionary, which I've accumulated

  • by making this walk.

  • Well, now let's look at this general case here and see how

  • that works.

  • Here we have it.

  • I take in a pattern variable--a pattern, an

  • expression, and a dictionary.

  • And now I'm going to do a complicated thing here, which

  • is the general case.

  • The expression is made out of two parts: a left and a right

  • half, in general.

  • Anything that's complicated is made out of two pieces in a

  • Lisp system.

  • Well, now what do we have here?

  • I'm going to match the car's of the two expressions against

  • each other with respect to the dictionary I already have,

  • producing a dictionary as its value, which I will then use

  • for matching the cdr's against each other.

  • So that's how the dictionary travels,

  • threads the entire structure.

  • And then the result of that is the dictionary for the match

  • of the car and the cdr, and that's what's going to be

  • returned as a value.

  • Now, at any point, a match might fail.

  • It may be the case, for example, if we go back and

  • look at an expression that doesn't quite match, like

  • supposing this was a 4.

  • Well, now these two don't match any more, because the x

  • that had to be-- sorry, the y that had to be x here and this

  • y has to be 4.

  • But x and 4 were not the same object syntactically.

  • So this wouldn't match, and that would be rejected

  • sometimes, so matches may fail.

  • Now, of course, because this matcher takes the dictionary

  • from the previous match as input, it must be able to

  • propagate the failures.

  • And so that's what the first clause of

  • this conditional does.

  • It's also true that if it turned out that the pattern

  • was not atomic--

  • see, if the pattern was atomic, I'd go into this

  • stuff, which we haven't looked at yet.

  • But if the pattern is not atomic and the

  • expression is atomic--

  • it's not made out of pieces--

  • then that must be a failure, and so we go over here.

  • If the pattern is not atomic and the pattern is not a

  • pattern variable--

  • I have to remind myself of that--

  • then we go over here.

  • So that way, failures may occur.

  • OK, so now let's look at the insides of this thing.

  • Well, the first place to look is what happens if I have an

  • atomic pattern?

  • That's very simple.

  • A pattern that's not made out of any pieces: foo.

  • That's a nice atomic pattern.

  • Well, here's what we see.

  • If the pattern is atomic, then if the expression is atomic,

  • then if they are the same thing, then the dictionary I

  • get is the same one as I had before.

  • Nothing's changed.

  • It's just that I matched plus against plus, asterisk against

  • asterisk, x against x.

  • That's all fine.

  • However, if the pattern is not the one which is the

  • expression, if I have two separate atomic objects, then

  • it was matching plus against asterisk, which case I fail.

  • Or if it turns out that the pattern is atomic but the

  • expression is complicated, it's not atomic,

  • then I get a failure.

  • That's very simple.

  • Now, what about the various kinds of pattern variables?

  • We had three kinds.

  • I give them the names.

  • They're arbitrary constants, arbitrary variables, and

  • arbitrary expressions.

  • A question mark x is an arbitrary expression.

  • A question mark cx is an arbitrary constant, and a

  • question mark vx is an arbitrary variable.

  • Well, what do we do here?

  • Looking at this, we see that if I have an arbitrary

  • constant, if the pattern is an arbitrary constant, then it

  • had better be the case that the expression

  • had better be a constant.

  • If the expression is not a constant,

  • then that match fails.

  • If it is a constant, however, then I wish to extend the

  • dictionary.

  • I wish to extend the dictionary with that pattern

  • being remembered to be that expression using the old

  • dictionary as a starting point.

  • So really, for arbitrary variables, I have to check

  • first if the expression is a variable by matching against.

  • If so, it's worth extending the dictionary so that the

  • pattern is remembered to be matched against that

  • expression, given the original dictionary, and this makes a

  • new dictionary.

  • Now, it has to check.

  • There's a sorts of failure inside extend dictionary,

  • which is that--

  • if one of these pattern variables already has a value

  • and I'm trying to match the thing against something else

  • which is not equivalent to the one that I've already matched

  • it against once, then a failure will come flying out

  • of here, too.

  • And I will see that some time.

  • And finally, an arbitrary expression does not have to

  • check anything syntactic about the expression that's being

  • matched, so all it does is it's an extension of the

  • dictionary.

  • So you've just seen a complete, very simple matcher.

  • Now, one of the things that's rather remarkable about this

  • is people pay an awful lot of money these days for someone

  • to make a, quote, AI expert system that has nothing more

  • in it than a matcher and maybe an instantiater like this.

  • But it's very easy to do, and now, of course, you can start

  • up a little start-up company and make a couple of megabucks

  • in the next week taking some people for a ride.

  • 20 years ago, this was remarkable,

  • this kind of program.

  • But now, this is sort of easy.

  • You can teach it to freshmen.

  • Well, now there's an instantiater as well.

  • The problem is they're all going off and making more

  • money than I do.

  • But that's always been true of universities.

  • As expression, the purpose of the instantiater is to make

  • expressions given a dictionary and a skeleton.

  • And that's not very hard at all.

  • We'll see that very simply in the next, the next slide here.

  • To instantiate a skeleton, given a particular

  • dictionary--

  • oh, this is easy.

  • We're going to do a recursive tree walk over the skeleton.

  • And for everything which is a skeleton variable--

  • I don't know, call it a skeleton evaluation.

  • That's the name and the abstract syntax that I give it

  • in this program: a skeleton evaluation, a thing beginning

  • with a colon in the rules.

  • For anything of that case, I'm going to look up the answer in

  • the dictionary, and we'll worry about that in a second.

  • Let's look at this as a whole.

  • Here, I have--

  • I'm going to instantiate a skeleton, given a dictionary.

  • Well, I'm going to define some internal loop right there, and

  • it's going to do something very simple.

  • Even if a skeleton--even if a skeleton is simple and atomic,

  • in which case it's nothing more than giving the skeleton

  • back as an answer, or in the general case, it's

  • complicated, in which case I'm going to make up the

  • expression which is the result of instantiating--

  • calling this loop recursively--

  • instantiating the car of the skeleton and the cdr.

  • So here is a recursive tree walk.

  • However, if it turns out to be a skeleton evaluation, a colon

  • expression in the skeleton, then what I'm going to do is

  • find the expression that's in the colon--

  • the CADR in this case.

  • It's a piece of abstract syntax here, so I can change

  • my representation of rules.

  • I'm going to evaluate that relative to this dictionary,

  • whatever evaluation means.

  • We'll find out a lot about that sometime.

  • And the result of that is my answer.

  • so.

  • I start up this loop-- here's my initialization--

  • by calling it with the whole skeleton, and this will just

  • do a recursive decomposition into pieces.

  • Now, one more little bit of detail is what

  • happens inside evaluate?

  • I can't tell you that in great detail.

  • I'll tell you a little bit of it.

  • Later, we're going to see--look into this in much

  • more detail.

  • To evaluate some form, some expression with respect to a

  • dictionary, if the expression is an atomic object, well, I'm

  • going to go look it up.

  • Nothing very exciting there.

  • Otherwise, I'm going to do something complicated here,

  • which is I'm going to apply a procedure which is the result

  • of looking up the operator part in something that we're

  • going to find out about someday.

  • I want you realize you're seeing magic now.

  • This magic will become clear very soon, but not today.

  • Then I'm looking at--looking up all the pieces, all the

  • arguments to that in the dictionary.

  • So I don't want you to look at this in detail.

  • I want you to say that there's more going on here, and we're

  • going to see more about this.

  • But it's--

  • the magic is going to stop.

  • This part has to do with Lisp, and it's the end of that.

  • OK, so now we know about matching and instantiation.

  • Are there any questions for this segment?

  • AUDIENCE: I have a question.

  • PROFESSOR: Yes.

  • AUDIENCE: Is it possible to bring up a previous slide?

  • It's about this define match pattern.

  • PROFESSOR: Yes.

  • You'd like to see the overall slide define match pattern.

  • Can somebody put up the--

  • no, the overhead.

  • That's the biggest scale one.

  • What part would you like to see?

  • AUDIENCE: Well, the top would be fine.

  • Any of the parts where you're passing failed.

  • PROFESSOR: Yes.

  • AUDIENCE: The idea is to pass failed back to the dictionary;

  • is that right?

  • PROFESSOR: The dictionary is the answer to a match, right?

  • And it is either some mapping or there's no match.

  • It doesn't match.

  • AUDIENCE: Right.

  • PROFESSOR: So what you're seeing over here is, in fact,

  • because the fact that a match may have another match pass in

  • the dictionary, as you see in the general case down here.

  • Here's the general case where a match passes another match

  • to the dictionary.

  • When I match the cdr's, I match them in the dictionary

  • that is resulting from matching the car's.

  • OK, that's what I have here.

  • So because of that, if the match of the car's fails, then

  • it may be necessary that the match of the cdr's propagates

  • that failure, and that's what the first line is.

  • AUDIENCE: OK, well, I'm still unclear what matches--

  • what comes out of one instance of the match?

  • PROFESSOR: One of two possibilities.

  • Either the symbol failed, which means there is no match.

  • AUDIENCE: Right.

  • PROFESSOR: Or some mapping, which is an abstract thing

  • right now, and you should know about the structure of it,

  • which relates the pattern variables to their values as

  • picked up in the match.

  • AUDIENCE: OK, so it is--

  • PROFESSOR: That's constructed by extend dictionary.

  • AUDIENCE: So the recursive nature brings about the fact

  • that if ever a failed gets passed out of any calling of

  • match, then the first condition will pick it up--

  • PROFESSOR: And just propagate it along without any further

  • ado, right.

  • AUDIENCE: Oh, right.

  • OK.

  • PROFESSOR: That's just the fastest way to get that

  • failure out of there.

  • Yes.

  • AUDIENCE: If I don't fail, that means that I've matched a

  • pattern, and I run the procedure extend dict and then

  • pass in the pattern in the expression.

  • But the substitution will not be made at that

  • point; is that right?

  • I'm just--

  • PROFESSOR: No, no.

  • There's no substitution being there because there's no

  • skeleton to be substituted in.

  • AUDIENCE: Right.

  • So what--

  • PROFESSOR: All you've got there is we're making up the

  • dictionary for later substitution.

  • AUDIENCE: And what would the dictionary look like?

  • Is it ordered pairs?

  • PROFESSOR: That's--that's not told to you.

  • We're being abstract.

  • AUDIENCE: OK.

  • PROFESSOR: Why do you want to know?

  • What it is, it's a function.

  • It's a function.

  • AUDIENCE: Well, the reason I want to know is--

  • PROFESSOR: A function abstractly is a

  • set of ordered pairs.

  • It could be implemented as a set of list pairs.

  • It could be implemented as some fancy table mechanism.

  • It could be implemented as a function.

  • And somehow, I'm building up a function.

  • But I'm not telling you.

  • That's up to George, who's going to build that later.

  • I know you really badly want to write concrete things.

  • I'm not going to let you do that.

  • AUDIENCE: Well, let me at least ask, what is the

  • important information there that's being

  • passed to extend dict?

  • I want to pass the pattern I found--

  • PROFESSOR: Yes.

  • The pattern that's matched against the expression.

  • You want to have the pattern, which happens to be in those

  • cases pattern variables, right?

  • All of those three cases for extend

  • dict are pattern variables.

  • AUDIENCE: Right.

  • PROFESSOR: So you have a pattern variable that is to be

  • given a value in a dictionary.

  • AUDIENCE: Mm-hmm.

  • PROFESSOR: The value is the expression that it matched

  • against. The dictionary is the set of things I've already

  • figured out that I have memorized or learned.

  • And I am going to make a new dictionary, which is extended

  • from the original one by having that pattern variable

  • have a value with the new dictionary.

  • AUDIENCE: I guess what I don't understand is why can't the

  • substitution be made right as soon as you find--

  • PROFESSOR: How do I know what I'm going to substitute?

  • I don't know anything about this skeleton.

  • This pattern, this matcher is an independent unit.

  • AUDIENCE: Oh, I see.

  • OK.

  • PROFESSOR: Right?

  • AUDIENCE: Yeah.

  • PROFESSOR: I take the matcher.

  • I apply the matcher.

  • If it matches, then it was worth doing instantiation.

  • AUDIENCE: OK, good.

  • Yeah.

  • PROFESSOR: OK?

  • AUDIENCE: Can you just do that answer again using that

  • example on the board?

  • You know, what you just passed back to the matcher.

  • PROFESSOR: Oh yes.

  • OK, yes.

  • You're looking at this example.

  • At this point when I'm traversing this structure, I

  • get to here: x.

  • I have some dictionary, presumably an empty dictionary

  • at this point if this is the whole expression.

  • So I have an empty dictionary, and I've matched x against 3.

  • So now, after this point, the dictionary

  • contains x is 3, OK?

  • Now, I continue walking along here.

  • I see y.

  • Now, this is a particular x, a pattern x.

  • I see y, a pattern y.

  • The dictionary says, oh yes, the pattern y is the symbol x

  • because I've got a match there.

  • So the dictionary now contains at this point two entries.

  • The pattern x is 3, and the pattern y is the expression x.

  • Now, I get that, I can walk along further.

  • I say, oh, pattern y also wants to be 4.

  • But that isn't possible, producing a failure.

  • Thank you.

  • Let's take a break.

  • OK, you're seeing your first very big and hairy program.

  • Now, of course, one of the goals of this subsegment is to

  • get you to be able to read something like this and not be

  • afraid of it.

  • This one's only about four pages of code.

  • By the end of the subject, I hope a 50-page program will

  • not look particularly frightening.

  • But I don't expect-- and I don't want you to think that I

  • expect you to be getting it as it's coming out.

  • You're supposed to feel the flavor of this, OK?

  • And then you're supposed to think about it because it is a

  • big program.

  • There's a lot of stuff inside this program.

  • Now, I've told you about the language we're implementing,

  • the pattern match substitution language.

  • I showed you some rules.

  • And I've told you about matching and instantiation,

  • which are the two halves of how a rule works.

  • Now we have to understand the control structure by which the

  • rules are applied to the expressions so as to do

  • algebraic simplification.

  • Now, that's also a big complicated mess.

  • The problem is that there is a variety of interlocking,

  • interwoven loops, if you will, involved in this.

  • For one thing, I have to apply--

  • I have to examine every subexpression of my expression

  • that I'm trying to simplify.

  • That we know how to do.

  • It's a car cdr recursion of some sort, or something like

  • that, and some sort of tree walk.

  • And that's going to be happening.

  • Now, for every such place, every node that I get to in

  • doing my traversal of the expression I'm trying to

  • simplify, I want to apply all of the rules.

  • Every rule is going to look at every node.

  • I'm going to rotate the rules around.

  • Now, either a rule will or will not match.

  • If the rule does not match, then it's not very

  • interesting.

  • If the rule does match, then I'm going to replace that node

  • in the expression by an alternate expression.

  • I'm actually going to make a new

  • expression, which contains--

  • everything contains that new value, the result of

  • substituting into the skeleton, instantiating the

  • skeleton for that rule at this level.

  • But no one knows whether that thing that I instantiated

  • there is in simplified form.

  • So we're going to have to simplify that, somehow to call

  • the simplifier on the thing that I just constructed.

  • And then when that's done, then I sort of can build that

  • into the expression I want as my answer.

  • Now, there is a basic idea here, which I will call a

  • garbage- in, garbage-out simplifier.

  • It's a kind of recursive simplifier.

  • And what happens is the way you simplify something is that

  • simple objects like variables are simple.

  • Compound objects, well, I don't know.

  • What I'm going to do is I'm going to build up from simple

  • objects, trying to make simple things by assuming that the

  • pieces they're made out of are simple.

  • That's what's happening here.

  • Well, now, if we look at the first slide--

  • no, overhead, overhead.

  • If we look at the overhead, we see a very complicated program

  • like we saw before for the matcher, so complicated that

  • you can't read it like that.

  • I just want you to get the feel of the shape of it, and

  • the shape of it is that this program has various

  • subprograms in it.

  • One of them--this part is the part for traversing the

  • expression, and this part is the part for trying rules.

  • Now, of course, we can look at that in some more detail.

  • Let's look at--let's look at the first transparency, right?

  • The simplifier is made out of several parts.

  • Now, remember at the very beginning, the simplifier is

  • the thing which takes a rules--a set of rules and

  • produces a program which will simplify it relative to them.

  • So here we have our simplifier.

  • It takes a rule set.

  • And in the context where that rule set is defined, there are

  • various other definitions that are done here.

  • And then the result of this simplifier procedure is, in

  • fact, one of the procedures that was defined.

  • Simplify x.

  • What I'm returning as the value of calling the

  • simplifier on a set of rules is a procedure, the simplify x

  • procedure, which is defined in that context, which is a

  • simplification procedure appropriate for using those

  • set of rules.

  • That's what I have there.

  • Now, the first two of these procedures, this one and this

  • one, are together going to be the recursive traversal of an

  • expression.

  • This one is the general simplification for any

  • expression, and this is the thing which simplifies a list

  • of parts of an expression.

  • Nothing more.

  • For each of those, we're going to do something complicated,

  • which involves trying the rules.

  • Now, we should look at the various parts.

  • Well let's look first at the recursive traversal of an

  • expression.

  • And this is done in a sort of simple way.

  • This is a little nest of recursive procedures.

  • And what we have here are two procedures--

  • one for simplifying an expression, and one for

  • simplifying parts of an expression.

  • And the way this works is very simple.

  • If the expression I'm trying to simplify is a compound

  • expression, I'm going to simplify all the parts of it.

  • And that's calling--that procedure, simplify parts, is

  • going to make up a new expression with all the parts

  • simplified, which I'm then going to try the

  • rules on over here.

  • If it turns out that the expression is not compound, if

  • it's simple, like just a symbol or something like pi,

  • then in any case, I'm going to try the rules on it because it

  • might be that I want in my set of rules to expand pi to

  • 3.14159265358979, dot, dot, dot.

  • But I may not.

  • But there is no reason not to do it.

  • Now, if I want to simplify the parts, well, that's easy too.

  • Either the expression is an empty one, there's no more

  • parts, in which case I have the empty expression.

  • Otherwise, I'm going to make a new expression by cons, which

  • is the result of simplifying the first part of the

  • expression, the car, and simplifying the rest of the

  • expression, which is the cdr.

  • Now, the reason why I'm showing you this sort of stuff

  • this way is because I want you get the feeling for the

  • various patterns that are very important when writing

  • programs. And this could be written a different way.

  • There's another way to write simplified expressions so

  • there would be only one of them.

  • There would only be one little procedure here.

  • Let me just write that on the blackboard to give you a

  • feeling for that.

  • This in another idiom, if you will.

  • To simplify an expression called x, what

  • am I going to do?

  • I'm going to try the rules on the following situation.

  • If--

  • on the following expression--

  • compound, just like we had before.

  • If the expression is compound, well, what am I going to do?

  • I'm going to simplify all the parts.

  • But I already have a cdr recursion, a common pattern of

  • usage, which has been captured as a high-order procedure.

  • It's called map.

  • So I'll just write that here.

  • Map simplify the expression, all the parts of the

  • expression.

  • This says apply the simplification operation,

  • which is this one, every part of the expression, and then

  • that cuts those up into a list. It's every element of

  • the list which the expression is assumed to be made out of,

  • and otherwise, I have the expression.

  • So I don't need the helper procedure, simplify parts,

  • because that's really this.

  • So sometimes, you just write it this way.

  • It doesn't matter very much.

  • Well, now let's take a look at--

  • let's just look at how you try rules.

  • If you look at this slide, we see this is a

  • complicated mess also.

  • I'm trying rules on an expression.

  • It turns out the expression I'm trying it on is some

  • subexpression now of the expression I started with.

  • Because the thing I just arranged allowed us to try

  • every subexpression.

  • So now here we're taking in a subexpression of the

  • expression we started with.

  • That's what this is.

  • And what we're going to define here is a procedure called

  • scan, which is going to try every rule.

  • And we're going to start it up on the whole set of rules.

  • This is going to go cdr-ing down the rules, if you will,

  • looking for a rule to apply.

  • And when it finds one, it'll do the job.

  • Well, let's take a look at how try rules works.

  • It's very simple: the scan rules.

  • Scan rules, the way of scanning.

  • Well, is it so simple?

  • It's a big program, of course.

  • We take a bunch of rules, which is a sublist

  • of the list of rules.

  • We've tried some of them already, and they've not been

  • appropriate, so we get to some here.

  • We get to move to the next one.

  • If there are no more rules, well then, there's nothing I

  • can do with this expression, and it's simplified.

  • However, if it turns out that there are still rules to be

  • done, then let's match the pattern of the first rule

  • against the expression using the empty dictionary to start

  • with and use that as the dictionary.

  • If that happens to be a failure, try

  • the rest of the rules.

  • That's all it says here.

  • It says discard that rule.

  • Otherwise, well, I'm going to get the skeleton of the first

  • rule, instantiate that relative to the dictionary,

  • and simplify the result, and that's the expression I want.

  • So although that was a complicated program, every

  • complicated program is made out of a lot of simple pieces.

  • Now, the pattern of recursions here is very complicated.

  • And one of the most important things is not

  • to think about that.

  • If you try to think about the actual pattern by which this

  • does something, you're going to get very confused.

  • I would.

  • This is not a matter of you can do this with practice.

  • These patterns are hard.

  • But you don't have to think about it.

  • The key to this--

  • it's very good programming and very good design-- is to know

  • what not to think about.

  • The fact is, going back to this slide, I don't have to

  • think about it because I have specifications in my mind for

  • what simplify x does.

  • I don't have to know how it does it.

  • And it may, in fact, call scan somehow through try rules,

  • which it does.

  • And somehow, I've got another recursion going on here.

  • But since I know that simplify x is assumed by wishful

  • thinking to produce the simplified result, then I

  • don't have to think about it anymore.

  • I've used it.

  • I've used it in a reasonable way.

  • I will get a reasonable answer.

  • And you have to learn how to program that way--

  • with abandon.

  • Well, there's very little left of this thing.

  • All there is left is a few details associated with what a

  • dictionary is.

  • And those of you who've been itching to know what a

  • dictionary is, well, I will flip it up and not tell you

  • anything about it.

  • Dictionaries are easy.

  • It's represented in terms of something else called an A

  • list, which is a particular pattern of usage for making

  • tables in lists.

  • They're easy.

  • They're made out of pairs, as was asked a bit ago.

  • And there are special procedures for dealing with

  • such things called assq, and you can find them in manuals.

  • I'm not terribly excited about it.

  • The only interesting thing here in extend dictionary is I

  • have to extend the dictionary with a pattern, a datum, and a

  • dictionary.

  • This pattern is, in fact, at this point a pattern variable.

  • And what do I want to do?

  • I want to pull out the name of that pattern variable, the

  • pattern variable name, and I'm going to look up in the

  • dictionary and see if it already has a value.

  • If not, I'm going to add a new one in.

  • If it does have one, if it has a value, then it had better be

  • equal to the one that was already stored away.

  • And if that's the case, the dictionary is what I

  • expected it to be.

  • Otherwise, I fail.

  • So that's easy, too.

  • If you open up any program, you're going to find inside of

  • it lots of little pieces, all of which are easy.

  • So at this point, I suppose, I've just told you some

  • million-dollar valuable information.

  • And I suppose at this point we're pretty much done with

  • this program.

  • I'd like to ask about questions.

  • AUDIENCE: Yes, can you give me the words that describe the

  • specification for a simplified expression?

  • PROFESSOR: Sure.

  • A simplified expression takes an expression and produces a

  • simplified expression.

  • That's it, OK?

  • How it does it is very easy.

  • In compound expressions, all the pieces are simplified, and

  • then the rules are tried on the result.

  • And for simple expressions, you just try all the rules.

  • AUDIENCE: So an expression is simplified by

  • virtue of the rules?

  • PROFESSOR: That's, of course, true.

  • AUDIENCE: Right.

  • PROFESSOR: And the way this works is that simplifi

  • expression, as you see here, what it does is it breaks the

  • expression down into the smallest pieces, simplifies

  • building up from the bottom using the rules to be the

  • simplifier, to do the manipulations, and constructs

  • a new expression as the result.

  • Eventually, one of things you see is that the rules

  • themselves, the try rules, call a simplified expression

  • on the results when it changes something, the

  • results of a match.

  • I'm sorry, the results of instantiation of a skeleton

  • for a rule that has matched.

  • So the spec of a simplified expression is that any

  • expression you put into it comes out simplified according

  • to those rules.

  • Thank you.

  • Let's take a break.

PROFESSOR: Well, yesterday we learned a bit about symbolic

Subtitles and vocabulary

Click the word to look it up Click the word to find further inforamtion about it