6.001 Structure and Interpretation of Computer Programs. Copyright o 2004 by Massachusetts Institute of Technology 6.001 Notes: Section 30.1 Slide 30l1 In this lecture, we are going to go back to several themes that 6.001: Structure and Interpretation of we have been exploring over the past few weeks, and stitch Computer Programs using the tools we have been building for dealing with stea.see them together into a single demonstration. We are going to see Today how quickly we can describe and control a complex system, by Building a new language using data and procedure abstractions abstractions 8n003 60015e Slide 30.1.2 Themes to be integrated The themes we are going to utilize include the following We are going to build on the idea of data abstraction, especially arate use of data structure from details of data the idea of separating the use of a data structure from the details Procedural abstraction of its implementation. We are going to see how that abstraction apture common patterns of behavior and treat as black barrier enables us to quickly describe complex structures box for generating new patterns Means of combination without getting lost in their details, and how to focus on the use Create complex combinations, then treat as primitives of such structures as entire units, while being assured that the interior details will be handled correctly Use modularity of components to create new language for particular problem domain We are going to also build on the idea of procedural abstraction d 8n/403 l especially the idea of capturing common patterns inside a black box, and using such abstractions to capture more complex And we are going to build on the idea of means of combination, that is, the idea that we can create simple methods for combining primitive objects into complex things, then treating the result as a primitive within a still more don plex thing. This will allow us to control complexity by utilizing a modular decomposition of the problem So our goal is to pull these pieces together to build a new language, one that is specifically designed for a particular problem domain
6.001 Structure and Interpretation of Computer Programs. Copyright © 2004 by Massachusetts Institute of Technology. 6.001 Notes: Section 30.1 Slide 30.1.1 In this lecture, we are going to go back to several themes that we have been exploring over the past few weeks, and stitch them together into a single demonstration. We are going to see how quickly we can describe and control a complex system, by using the tools we have been building for dealing with abstractions. Slide 30.1.2 The themes we are going to utilize include the following. We are going to build on the idea of data abstraction, especially the idea of separating the use of a data structure from the details of its implementation. We are going to see how that abstraction barrier enables us to quickly describe complex structures without getting lost in their details, and how to focus on the use of such structures as entire units, while being assured that the interior details will be handled correctly. We are going to also build on the idea of procedural abstraction, especially the idea of capturing common patterns inside a black box, and using such abstractions to capture more complex patterns. And we are going to build on the idea of means of combination, that is, the idea that we can create simple methods for combining primitive objects into complex things, then treating the result as a primitive within a still more complex thing. This will allow us to control complexity by utilizing a modular decomposition of the problem domain. So our goal is to pull these pieces together to build a new language, one that is specifically designed for a particular problem domain
6.001 Structure and Interpretation of Computer Programs. Copyright o 2004 by Massachusetts Institute of Technology Slide 30.1.3 So what problem domain should we use? Well, we are going to target-the art of M. C. Escher create a language that describes pictures such as this famous one by m.C. Escher, called"quadratlimit"or"square limit". Not only will our language let us describe the process by which such pictures can be created, it will also let us create our own variations on this theme, leading to pictures that have a resemblance to the kind of elegant structure shown here in this Escher print 8m00 Slide 30.1. 4 So how do we describe such a system? Well, let's start with a simpler example. Here is a picture of my friend George. At an abstract level. what kinds of things would i like to do with George? 6001 SICP Slide 30.1.5 First, I might like to flip him, either about the vertical axis or about the horizontal one. By this I mean literally taking this portrait of George and spinning it 180 degrees out of the plane, then setting it back down 4 87/2003 6m13P Slide 30.1.6 V/ Alternatively, I might like to rotate him about an axis coming out the picture, causing him to do a cartwheel as I rotate his picture by increments of 90 degrees. Conceptually this is easy If I think of George as a picture, I can easily envision grabbi the whole picture and doing something to it. But how do i do this in practice? 6001S1CP
6.001 Structure and Interpretation of Computer Programs. Copyright © 2004 by Massachusetts Institute of Technology. Slide 30.1.3 So what problem domain should we use? Well, we are going to create a language that describes pictures such as this famous one by M.C. Escher, called "quadratlimit" or "square limit". Not only will our language let us describe the process by which such pictures can be created, it will also let us create our own variations on this theme, leading to pictures that have a resemblance to the kind of elegant structure shown here in this Escher print. Slide 30.1.4 So how do we describe such a system? Well, let's start with a simpler example. Here is a picture of my friend George. At an abstract level, what kinds of things would I like to do with George? Slide 30.1.5 First, I might like to flip him, either about the vertical axis or about the horizontal one. By this I mean literally taking this portrait of George and spinning it 180 degrees out of the plane, then setting it back down. Slide 30.1.6 Alternatively, I might like to rotate him about an axis coming out the picture, causing him to do a cartwheel as I rotate his picture by increments of 90 degrees. Conceptually this is easy. If I think of George as a picture, I can easily envision grabbing the whole picture and doing something to it. But how do I do this in practice?
6.001 Structure and Interpretation of Computer Programs. Copyright o 2004 by Massachusetts Institute of Technology Slide 30.1.7 Here is one straightforward way. Assume that we have some a procedural definition of geor primitive drawing method called ( define(ge。 rge rect) (draw-line reet .250.35.5) draw-line r x1xt4:5.35 that takes a rectangle as input, and a set of coordinate values (e.g. x and y start point, and x and y end point), and draws a 89911.0g line from start to end within that rectangle. Note, details of the rectangle are irrelevant, we are just burying them beneath the abstraction. Thus, the first expression would draw a line starting 25 units to the right of the lower left hand corner, and ending at /4 enmatdtraw-line rect.15.60,85)) a point. 35 units to the right and 5 units up from the lower left hand corner Given that, here is a definition of George. Note what this does. Each expression gives a start and end point relative to the origin of the rectangle, and draw-line then sketches the line between those points Blech! This is far too specific, right? Given this definition of George, how do i create a rotated George or a flipped George? This is not obvious, and for an important reason. Here I have intertwined the action of drawing with the data representing George. I have not separated those actions, and moreover, I have chosen a very low-level representation for the elements of George. I really need to isolate these two aspects if I am to have any hope of drawing different pictures of George Slide 30.1.8 Data abstractions for lines So lets fix this. first we need some data abstractions to isolate points from the use of points. What is a point or a vector? It is define p1(make-vect 23))just a way of gluing together an x coordinate and ay (xcor p1))2 coordinate. so we can create an abstraction for this This has a (ycor p1)+3 constructor(called ma ke-vect) and two selectors(called xcor and yor) 48 1001 SICP Slide 30.1.9 Note that there is an inherent contract between these two Data abstractions for lines components: whatever method we use to glue things together in the constructor, we can get the parts back out using the efine pi(make-vect23》 selectors but the details of how we do that don t matter to p1)→2 things that simply want to use these objects rp1)→3 48m 6001CP
6.001 Structure and Interpretation of Computer Programs. Copyright © 2004 by Massachusetts Institute of Technology. Slide 30.1.7 Here is one straightforward way. Assume that we have some primitive drawing method called draw-line, that takes a rectangle as input, and a set of coordinate values (e.g. x and y start point, and x and y end point), and draws a line from start to end within that rectangle. Note, details of the rectangle are irrelevant, we are just burying them beneath the abstraction. Thus, the first expression would draw a line starting .25 units to the right of the lower left hand corner, and ending at a point .35 units to the right and .5 units up from the lower left hand corner. Given that, here is a definition of George. Note what this does. Each expression gives a start and end point, relative to the origin of the rectangle, and draw-line then sketches the line between those points. Blech! This is far too specific, right? Given this definition of George, how do I create a rotated George or a flipped George? This is not obvious, and for an important reason. Here I have intertwined the action of drawing with the data representing George. I have not separated those actions, and moreover, I have chosen a very low-level representation for the elements of George. I really need to isolate these two aspects if I am to have any hope of drawing different pictures of George. Slide 30.1.8 So let's fix this. First, we need some data abstractions, to isolate points from the use of points. What is a point or a vector? It is just a way of gluing together an x coordinate and a y coordinate, so we can create an abstraction for this. This has a constructor (called make-vect) and two selectors (called xcor and ycor). Slide 30.1.9 Note that there is an inherent contract between these two components: whatever method we use to glue things together in the constructor, we can get the parts back out using the selectors, but the details of how we do that don’t matter to things that simply want to use these objects
6.001 Structure and Interpretation of Computer Programs. Copyright o 2004 by Massachusetts Institute of Technology Data abstractions for lines Similarly, we can glue two endpoints or vectors together to eate a line segment. T data abstractie contract between the constructor (make-segment)and (define p1((make-vect 2 3) the selectors(start-segment and end p1)→3 segment (define p2 (make-vect 5 4)) So this gives us a way of abstracting vectors and segments Define s1 tmake-segmentp1 p2" Note the key point: I don' t need to know the details of how Ixcor tstart-segment s 1>2 vectors and segments are built, I just rely on the contract.This lycor tend-segment s ))>4 means we could think of George in terms of the appropriate elements, namely lines, rather than details of how those lines are represented Slide 30.1.l1 a better George So here is george in this format. Now, it looks like we have just put some window dressing around the line segments. But hang ta mm pf mahe wd 由mnr9-11m on, as we will see how treating George as an abstraction is going to make life much easier for us. In particular, note that fmet here we have created an abstraction for the points, and a separate abstraction for the line segments. Moreover, these are mm w omarm now defined with respect to some coordinate frame, they are not actually being drawn yet. So we have also separated the act mm l mrm of drawing from the representation of the data to be drawn dtn p22 trau veet.,》》 6 001 SICP Slide 30.1.12 Gluing things together First though, how could we actually build these vectors and For pairs, use a cons: 凵 Well, you saw this in the last lecture. For pairs of things (i.e things that come naturally in twos), we could just use a cons For larger structures. use a list: cell or a pair. And for larger collections, we could use lists. And of courses lists are just sequences of cons cells glued together into a spine, with the elements hanging off of it. ist1234) (cons I(cons 2(cons 3(cons d niD)))
6.001 Structure and Interpretation of Computer Programs. Copyright © 2004 by Massachusetts Institute of Technology. Slide 30.1.10 Similarly, we can glue two endpoints or vectors together to create a line segment. This again is a data abstraction, with a contract between the constructor (make-segment) and the selectors (start-segment and endsegment). So this gives us a way of abstracting vectors and segments. Note the key point: I don't need to know the details of how vectors and segments are built, I just rely on the contract. This means we could think of George in terms of the appropriate elements, namely lines, rather than details of how those lines are represented. Slide 30.1.11 So here is George in this format. Now, it looks like we have just put some window dressing around the line segments. But hang on, as we will see how treating George as an abstraction is going to make life much easier for us. In particular, note that here we have created an abstraction for the points, and a separate abstraction for the line segments. Moreover, these are now defined with respect to some coordinate frame; they are not actually being drawn yet. So we have also separated the act of drawing from the representation of the data to be drawn. Slide 30.1.12 First though, how could we actually build these vectors and segments? Well, you saw this in the last lecture. For pairs of things (i.e. things that come naturally in twos), we could just use a cons cell or a pair. And for larger collections, we could use lists. And of courses lists are just sequences of cons cells glued together into a spine, with the elements hanging off of it
6.001 Structure and Interpretation of Computer Programs. Copyright o 2004 by Massachusetts Institute of Technology Slide 30.1.13 Remember that there are several important properties to pairs Properties of data structures and lists. They have a contract between constructor and Contract between constructor and selectors selectors. They have the property of closure that is, that the Property of closure result of creating an instance of an object can itself be used to A list is a sequence of pairs, ending in the create a new object empty list, nil This is worth exploring a bit more carefully. So what is a list? It Consing anything onto a list results in a list(by is a sequence of pairs, ending in the special symbol nil, or definition) empty list. Thus, consing anything onto a list gives you a new Taking the cdr of a list results in a list(except perhaps for the empty list) sequence of pairs, ending in the empty list, hence a list Would be better to use adjoin, first and rest, Similarly, taking the cdr of a sequence of pairs ending in the instead of cons car and cdr. empty list results in a shorter sequence of pairs ending in the 4 &2003 6001S empty list, and hence is a list. Thus lists are closed under the operations of cons and cdr Note that this is not quite right. What happens if you try to take the cdr of nil? In MIT Scheme you get an error, but by this definition it would be better to just return the empty list Also notice that it would really be better to have distinctive operations for lists, as compared to pairs, e.g. adjoin first and rest, instead of cons, car and cdr, to distinguish operations on lists from operations on pairs. For historical reasons, we stick with the latter, even though the better would be conceptually much cleaner Slide 30.1.14 Completing our abstraction So let's use this to build a specific version of our abstraction Note how our abstraction nicely inherits its contract from the Points or vectors: underlying contract for pairs and lists. And note how points create a nested structure underneath lines. That is a line (define yor cdr] segment is a list of two elements, each of which points to Line segments: 山啁 another abstraction, namely a pair representing a vector (define makesegment list) (define start-segment car) 6 001 SICP Slide 30.1.15 Okay, now let's put the pieces together. George is just defined Drawing in a rectangle or frame as a collection(a list in this case)of line segments. All we need to do is take a rectangle or frame(which is just a pair of orthogonal line segments), and draw these segments within that rectangle. But as we start thinking towards the kinds of operations we did on George earlier. we would like to be able to draw george in different frames. So we would like to be able to define any frame. either of different size. or even non-orthogonal. and draw George inside of it. What does that mean? Ideally, we could take George( defined as a set of segments within a frame) and stretch those segments to fit within a new frame
6.001 Structure and Interpretation of Computer Programs. Copyright © 2004 by Massachusetts Institute of Technology. Slide 30.1.13 Remember that there are several important properties to pairs and lists. They have a contract between constructor and selectors. They have the property of closure, that is, that the result of creating an instance of an object can itself be used to create a new object. This is worth exploring a bit more carefully. So what is a list? It is a sequence of pairs, ending in the special symbol nil, or empty list. Thus, consing anything onto a list gives you a new sequence of pairs, ending in the empty list, hence a list. Similarly, taking the cdr of a sequence of pairs ending in the empty list results in a shorter sequence of pairs ending in the empty list, and hence is a list. Thus lists are closed under the operations of cons and cdr. Note that this is not quite right. What happens if you try to take the cdr of nil? In MIT Scheme you get an error, but by this definition it would be better to just return the empty list. Also notice that it would really be better to have distinctive operations for lists, as compared to pairs, e.g. adjoin, first and rest, instead of cons, car and cdr, to distinguish operations on lists from operations on pairs. For historical reasons, we stick with the latter, even though the better would be conceptually much cleaner. Slide 30.1.14 So let's use this to build a specific version of our abstraction. Note how our abstraction nicely inherits its contract from the underlying contract for pairs and lists. And note how points create a nested structure underneath lines. That is a line segment is a list of two elements, each of which points to another abstraction, namely a pair representing a vector. Slide 30.1.15 Okay, now let's put the pieces together. George is just defined as a collection (a list in this case) of line segments. All we need to do is take a rectangle or frame (which is just a pair of orthogonal line segments), and draw these segments within that rectangle. But as we start thinking towards the kinds of operations we did on George earlier, we would like to be able to draw George in different frames. So we would like to be able to define any frame, either of different size, or even non-orthogonal, and draw George inside of it. What does that mean? Ideally, we could take George (defined as a set of segments within a frame) and stretch those segments to fit within a new frame
6.001 Structure and Interpretation of Computer Programs. Copyright o 2004 by Massachusetts Institute of Technology Slide 30.1.16 Here is a nice way to build that abstraction. We'll create our Drawing in a rectangle or frame picture within the constraints of a default rectangle, of size 1 That is, our initial set of segments will have the property that their x and y values all lie between 0 and 1. Imagine those segments being attached to a sheet of rubber that fits over a square frame as shown in the lower left Then, if we provide other rectangle, which may be shifted 1,1) over from the first, and which may have a different aspect ratio we want our method for drawing to take that sheet of rubber and stretch it to fit over the new rectangle's fra (0, 0)en/203 Slide 30.1.17 Well that is fine, we just need another data structure. Note that Generating the abstraction of a frame this one is built out of vectors, so we are constructing another define make- rectangle lis abstraction within our system. In particular, a rectangle is now defined to have a vector to its origin or starting point, and two (define horiz cadre vectors that specify the extent of the horizontal and vertical efine vert cadd) Generating the abstraction of a frame Slide 30.1.1 8 And then a picture is just a procedure that takes a rectangle(one Rectangle: (define make-rectangle list) of these abstractions )and does some stuff to draw lines within (define origin car that rectangle. We will return shortly to what this actually (define horiz cadr] oes Slide 30.1. 19 Now a key issue in building data abstractions is that it should What happens if we change an abstraction? insulate the details of the abstraction from the actual use of the abstraction. To stress this, suppose we make the following (define xcor car) change to our data structures we change make-vect to (define yor cadr list, and we change ycor to cadr, which is short What else needs to change in our system? for(car (cdr .)) note that is version still satisfies our contract on the abstraction What else has to change inside of our system? 600Sc
6.001 Structure and Interpretation of Computer Programs. Copyright © 2004 by Massachusetts Institute of Technology. Slide 30.1.16 Here is a nice way to build that abstraction. We'll create our picture within the constraints of a default rectangle, of size 1. That is, our initial set of segments will have the property that their x and y values all lie between 0 and 1. Imagine those segments being attached to a sheet of rubber that fits over a square frame as shown in the lower left. Then, if we provide some other rectangle, which may be shifted over from the first, and which may have a different aspect ratio, we want our method for drawing to take that sheet of rubber and stretch it to fit over the new rectangle’s frame. Slide 30.1.17 Well that is fine, we just need another data structure. Note that this one is built out of vectors, so we are constructing another abstraction within our system. In particular, a rectangle is now defined to have a vector to its origin or starting point, and two vectors that specify the extent of the horizontal and vertical axes of the frame. Slide 30.1.18 And then a picture is just a procedure that takes a rectangle (one of these abstractions) and does some stuff to draw lines within that rectangle. We will return shortly to what this actually does. Slide 30.1.19 Now a key issue in building data abstractions is that it should insulate the details of the abstraction from the actual use of the abstraction. To stress this, suppose we make the following change to our data structures: we change make-vect to list, and we change ycor to cadr, which is short for (car (cdr .)). Note that is version still satisfies our contract on the abstraction. What else has to change inside of our system?
6.001 Structure and Interpretation of Computer Programs. Copyright o 2004 by Massachusetts Institute of Technology Slide 30.1.20 What happens if we change an abstraction? Absolutely nothing! This is a key point about the data abstractions. The modularity (define make-vect list) of the abstraction isolates changes within the abstraction from (define xcor car) Note that this still atisfies the contract the use of the abstraction hence any code that uses these (define yor cadr) abstractions will still run, even though the details within the abstraction have changed What else needs to change in our system? BUPKIS, NADA NOTHING Slide 30.1.21 Okay, so we can create the pieces of George. But how do we actually draw? What is a a picture? This is where the weird part comes in! We could just create a Could just create a general procedure to draw procedure to draw line segments. But we want the flexibility of collections of line segmen being able to use any frame to draw the same picture But want to have flexibility of using any frame to So we make a picture be a procedure! This definitely sounds weird!! a picture sounds like it should be a data structure, a we make a picture be a procedure! Captures the procedural abstraction of drawing collection of geometric entities, but we are going to make it a data within a frame procedure. Inside the procedure will reside those geometric entities, but that procedure will take as input a rectangle, then e emam scale the elements to fit within that rectangle, and display the result This seems odd, right? In principle, a picture is data, but we are choosing to represent it as a procedural abstraction that captures the process of drawing data in a frame Why? Primarily for flexibility. In this way, we have one procedure with inherent data, but it provides an infinite number of versions of the picture. This abstraction allows for very easy manipulation of a picture structure to get new versions. So let's see how that happens Slide 30.1.22 Manipulating vectors First, we need to manipulate the pieces of a picture, so that means we need ways to manipulate vectors themselves. Let's look at some standard things we would like to do with vectors seale-vec We would like to take two vectors and add them together to get a new vector. And we would like to stretch or scale a vector by scaling its x and y coordinates by the same amount 4 80/2003 1001 SICP
6.001 Structure and Interpretation of Computer Programs. Copyright © 2004 by Massachusetts Institute of Technology. Slide 30.1.20 Absolutely nothing! This is a key point about the data abstractions. The modularity of the abstraction isolates changes within the abstraction from the use of the abstraction. Hence any code that uses these abstractions will still run, even though the details within the abstraction have changed. Slide 30.1.21 Okay, so we can create the pieces of George. But how do we actually draw? This is where the weird part comes in! We could just create a procedure to draw line segments. But we want the flexibility of being able to use any frame to draw the same picture. So we make a picture be a procedure!! This definitely sounds weird!! A picture sounds like it should be a data structure, a collection of geometric entities, but we are going to make it a procedure. Inside the procedure will reside those geometric entities, but that procedure will take as input a rectangle, then scale the elements to fit within that rectangle, and display the result. This seems odd, right? In principle, a picture is data, but we are choosing to represent it as a procedural abstraction that captures the process of drawing data in a frame. Why? Primarily for flexibility. In this way, we have one procedure with inherent data, but it provides an infinite number of versions of the picture. This abstraction allows for very easy manipulation of a picture structure to get new versions. So let's see how that happens! Slide 30.1.22 First, we need to manipulate the pieces of a picture, so that means we need ways to manipulate vectors themselves. Let's look at some standard things we would like to do with vectors. We would like to take two vectors and add them together to get a new vector. And we would like to stretch or scale a vector by scaling its x and y coordinates by the same amount
6.001 Structure and Interpretation of Computer Programs. Copyright o 2004 by Massachusetts Institute of Technology Slide 30.1.23 So here is code to do this. For example, the first procedure takes(make .et -c r n) acor vay two vectors and adds them together to get a new vector. It does cor v1) bcor v2》) this by extracting the x and y components of the vectors, adding mke-vect ector eun them separately and then creating a new vector with those C factor (cor vect) values for the components. The second procedure takes a (define (-vect v1 v2) vector and a number, and stretches (or shrinks) the vector by I+vect v1 (scale-vect v2-1)) (define (rotate-vect v angle) that amount (let ('c(cos angle)) Rotation is just a matter of applying some trigonometry to the (s (sin angle))) (make-vect ((c(xcor v) vector to create a new vector a key thing to observe is how we inherit closure from the (+c ecor v)) underlying representation. For example, in +vect, v I could be fs(xcor v)))))) 82 6001S the result of some other +vect operation Slide 30.1.24 Select parts Also note the form: we extract the pieces, do some simpler operations, and then construct a new version of the same type of Compute more primitive ycorlvectn) (define(-vect v1 And notice how this nicely isolates the changes beneath the I+vect v1 (scale-vect v2-1m) abstraction barrier. If we change the abstraction implementation (define (rotate-vectv angle (let ((c (cos angle)) for vectors, none of these procedures need to change! 48m 6001 SICP Slide 30.1.25 Now we can use all these pieces to assemble a picture. The Creating a picture basic idea is to take a list of segments( defined as pairs of vectors using our nice data abstraction). This then gets passed to a procedure that generates a picture, that is, a new procedure with the data embedded within it Note that this make-picture procedure is a higher order procedure, it takes as input a list and creates as output a ocedure 6001 SIC?
6.001 Structure and Interpretation of Computer Programs. Copyright © 2004 by Massachusetts Institute of Technology. Slide 30.1.23 So here is code to do this. For example, the first procedure takes two vectors and adds them together to get a new vector. It does this by extracting the x and y components of the vectors, adding them separately and then creating a new vector with those values for the components. The second procedure takes a vector and a number, and stretches (or shrinks) the vector by that amount. Rotation is just a matter of applying some trigonometry to the vector to create a new vector. A key thing to observe is how we inherit closure from the underlying representation. For example, in +vect, v1 could be the result of some other +vect operation. Slide 30.1.24 Also note the form: we extract the pieces, do some simpler operations, and then construct a new version of the same type of object. And notice how this nicely isolates the changes beneath the abstraction barrier. If we change the abstraction implementation for vectors, none of these procedures need to change!! Slide 30.1.25 Now we can use all these pieces to assemble a picture. The basic idea is to take a list of segments (defined as pairs of vectors using our nice data abstraction). This then gets passed to a procedure that generates a picture, that is, a new procedure with the data embedded within it. Note that this make-picture procedure is a higher order procedure, it takes as input a list and creates as output a new procedure
6.001 Structure and Interpretation of Computer Programs. Copyright o 2004 by Massachusetts Institute of Technology Slide 30.1.26 To use a picture, we simply give it a rectangle(as a data Creating a picture abstraction) and the picture procedure will then display it on the screen inside that rectangle. Slide 30.1.27 So here is the code for doing that The picture abstraction Note that this is a higher order procedure it takes a list as input, (define tmake-picture seglis) and returns a procedure as output. That procedure when given a ligher order rectangle as input, will ask each of the lines segments in the data structure embedded within the procedure to draw itself, et((b(start-segment segment)) appropriately scaled within the rectangle. For-each is (e(end-segment segment) (xcor b) Just like map, except that it doesn't accumulate an answer as it walks down the list applying its internal lambda to each element segt》 The key thing to note is how we are using standard list operations to capture this procedural abstraction of a picture Slide 30.1.28 Drawing lines is just algebra Just to be careful. what should draw-line do?The idea is that this procedure is given a rectangle, which contains wing a line is just some algebra. If rectangle has an within it an origin vector, an x axis and a y axis.Draw-line point p with compenents and es mappe o th oint takes an x and y coordinate value of a point(defined in a canonical rectangle), and scales the new horizontal and vertical axes by those amounts, and then shifts this by the offset to the (1,1) origin, using the vector algebra shown. Doing this for two xac points automatically shifts and stretches a line to fit within the new rectangle 0,0
6.001 Structure and Interpretation of Computer Programs. Copyright © 2004 by Massachusetts Institute of Technology. Slide 30.1.26 To use a picture, we simply give it a rectangle (as a data abstraction) and the picture procedure will then display it on the screen inside that rectangle. Slide 30.1.27 So here is the code for doing that. Note that this is a higher order procedure: it takes a list as input, and returns a procedure as output. That procedure when given a rectangle as input, will ask each of the lines segments in the data structure embedded within the procedure to draw itself, appropriately scaled within the rectangle. For-each is just like map, except that it doesn't accumulate an answer as it walks down the list applying its internal lambda to each element. The key thing to note is how we are using standard list operations to capture this procedural abstraction of a picture. Slide 30.1.28 Just to be careful, what should draw-line do? The idea is that this procedure is given a rectangle, which contains within it an origin vector, an x axis and a y axis. Draw-line takes an x and y coordinate value of a point (defined in a canonical rectangle), and scales the new horizontal and vertical axes by those amounts, and then shifts this by the offset to the origin, using the vector algebra shown. Doing this for two points automatically shifts and stretches a line to fit within the new rectangle
6.001 Structure and Interpretation of Computer Programs. Copyright o 2004 by Massachusetts Institute of Technology Slide 30.1.29 So, just to complete this idea, here is a better definition of A better George Remember we have george-lines from before (detine g(makepicture george-lines) 8m00 Operations on pictures Slide 30.1.30 So what is the big deal? Well. george is abstraction(george-lines: a set of segments)and a rocedure(g: a process for drawing those lines within a rectangle). Note that g contains the information about the segments within it as part of the procedural abstraction This makes it quite easy to use George as a building block other pictures, and that is what we want to turn to next H Again, remember what a picture is: it's a procedure that takes a 6001 SICP mo rectangle as input, and scales its line segments to draw within the rectangle(or frame) So we can easily generalize this idea to arbitrary frames, not just rectangular ones. Remember that a frame is just a set of three vectors, an origin and two axes, so by picking vectors for axes that are not orthogonal, we get skewing for free To rotate a picture, we can just shift the axes, in particular, make the old horizontal axis vertical, and the old vertical axis the negative horizontal axis. If we do this, then we can see that drawing the picture within this new coordinate frame will accomplish the task of rotating the original picture Slide 30.1.31 Operations on picture and we can easily build code to do this. Note what this does, in(define (rotateso pict) a very cool way. Rotate 90 returns a picture, that is a procedure(lambda rect of one argument, a rectangle. That new picture asks the old +vect(origin rect picture to draw itself, but in a new frame. And that frame ply comes about by creating a new origin, a new horizontal tvert rect ale-vect(horiz rect axis and a new vertical axis, just as we sketched Also notice how nicely the data abstractions preserve the cleanliness of this code. It is very easy to see what is being done 6m13P
6.001 Structure and Interpretation of Computer Programs. Copyright © 2004 by Massachusetts Institute of Technology. Slide 30.1.29 So, just to complete this idea, here is a better definition of George. Slide 30.1.30 So what is the big deal? Well, George is now both a data abstraction (george-lines: a set of segments) and a procedure (g: a process for drawing those lines within a rectangle). Note that g contains the information about the segments within it as part of the procedural abstraction This makes it quite easy to use George as a building block in other pictures, and that is what we want to turn to next. Again, remember what a picture is: it's a procedure that takes a rectangle as input, and scales its line segments to draw within the rectangle (or frame). So we can easily generalize this idea to arbitrary frames, not just rectangular ones. Remember that a frame is just a set of three vectors, an origin and two axes, so by picking vectors for axes that are not orthogonal, we get skewing for free. To rotate a picture, we can just shift the axes, in particular, make the old horizontal axis vertical, and the old vertical axis the negative horizontal axis. If we do this, then we can see that drawing the picture within this new coordinate frame will accomplish the task of rotating the original picture. Slide 30.1.31 And we can easily build code to do this. Note what this does, in a very cool way. Rotate90 returns a picture, that is a procedure of one argument, a rectangle. That new picture asks the old picture to draw itself, but in a new frame. And that frame simply comes about by creating a new origin, a new horizontal axis and a new vertical axis, just as we sketched. Also notice how nicely the data abstractions preserve the cleanliness of this code. It is very easy to see what is being done here