You are on page 1of 4

, In this segment, we're going to introduce the struct construct in Racket, show you how it works, use it to come

up with a better implementation of our little arithmetic expression language, and then in the next segment we'll discuss why it's a better approach. So here's the new feature and how we're going to use it. You can have a special form that you write struct. Then the name of your struct. Then the names of the fields it's going to have. So here, I'm defining a foo struct. It's going to have fields bar, baz and quux. We'll see how to use this in just a second. It'll be obvious once I show you what functions are defined as a byproduct of creating this declaration, and I'll explain at the end of this segment what this transparent attribute is. And why I encourage using it. So when you have this struct declaration, a bunch of functions are added to the environment, once you evaluate this struct. The first thing you get, is you do get a function called foo, that takes three arguments, because this struct has three fields, evaluates those three arguments, and returns some new thing It's a foo. That has a bar field, a baz field, and a quux field holding the results of e1, e2, and e3. So in that sense a struct is like a record because it has these fields named bar, baz and quux. But it's more than that. Because we also gt a function foo question mark, that evaluates any expression at all in Racket, and returns true if and only if the result is something that was made from the foo function. So this is how we can take something and find out if it's a foo or not. And then we get Three functions for evaluating the fields, foo-bar, foo-baz, and foo-quux. So what foo-bar is, is it's just a function, just the name of the struct dash the name of the field, evaluates something. If that something, that result, was made with the foo function, the first thing I showed you, then you get the contents of the bar field. Otherwise, it's an error. If we call foo-bar on something that is not a foo, it's a runtime error. Similarly, foo-baz returns the baz field. Foo-quux returns the quux field. Okay? So it turns out these things can be used for idioms like our expression example. So what I'm going to show you in a minute, when I show you the interpreter. The new eval x function, is 4 struct definitions. For const, negate, add, and multiply. The

const needs 1 field I'll call int. Negate needs 1 field, which I'll call e for the subexpression. Add means 2 fields, e1 and e2. And multiply similarly for the subexpressions. So what we're doing with this collection of 4 struct definitions, is a lot like our ML data type binding. Because struct definitions are most like ML constructors. Not a data type binding. There is none of that when we're in a dynamically type language. But each of these is a lot like an m l constructor definition, which in m l was part of a data type definition. Because what you get when you define a struct, is you get a constructor, a function for making the thing. You get a tester, a function for finding out if you have one of the things. And you get extractor functions, data accessing functions for getting the various fields. So const would be a constructor, const? a tester, cost-int one of these extractor functions. So it's not pattern matching. This is a different approach. It's an approach I happen to like a little bit less but it works fine, it's efficient. And because we're in a dynamically-typed language, two things are not in this code that you see above. First of all, we never say anywhere in the language, these are all the kinds of expressions There are. That's for us to keep track of. And secondly we don't say what the types of teh fields are. There are ways to do that in racket, but this more dybnamically typed approach just says that any of contents can hold anything and it'll be up to us to make sure that multiply only holds expressions and const in it's field Only holds a number. So with that, let's look at the code. I have the struct definitions right here that I showed you on the slide. And, now we can write our e-mail x function. It's the same logic as we seen now in our previous implementation with list's. And with, NML. And that is, if you have a const using that const function that is part of the struct definition. Just return the entire struct, the entire const thing. If you have a negate, then use the negate e function that was created. Because we have a struct name negate with a field e on. This argument. The argument 2 eval x. So that's going to give back something when we call eval x with it. Hopefully, it will be a const. Because when I call const-int, that will get the underlying number, if the thing