# Laboratory: Exploring Lists

Summary: In this laboratory, you will explore not only the basic list operations, but also some applications of those operations in working with images.

## Preparation

No special preparation is needed for this lab.

## Exercises

### Exercise 1: Some Simple Lists

a. Using the `cons` procedure, build a one-element list that contains the value `"red"`. The result of your call should be `("red")`.

b. Use the `cons` procedure to build a list of the value 5 followed by the value `"red"`. The result of your call should be `(5 "red")`. Note that you will need to call `cons` twice to build this list.

c. Call the `cons` procedure to build a list of the value 2, followed by the value 5, followed by `"red"`. The result of your call should be `(2 5 "red")`. Note that you will need to call `cons` three times to build this list.

d. Build the same list as in step c, using `list` rather than `cons`.

### Exercise 2: Extracting Information from Lists

Consider the following list definition, which you can enter in the interactions pane of your work window.

```(define letters (list 'a 'b 'c 'd 'e 'f 'g 'h 'i))
```

a. What do you expect the result of `(car letters)` to be? Check your answer experimentally.

b. What do you expect the result of `(cdr letters)` to be? Check your answer experimentally.

c. What do you expect the result of `(car (cdr letters))` to be? Check your answer experimentally.

d. What do you expect the result of `(cdr (cdr letters))` to be? Check your answer experimentally.

e. What do you expect the result of `(cdr (car letters))` to be? Check your answer experimentally.

f. Write an expression using `car` and `cdr` that extracts the sixth element of `letters`. (That is, your expression should extract the `f`.)

### Exercise 3: Other List Operations

a. Create the list `("red" "orange" "yellow")` and name it `roy`. Create the list `("green" "blue")` and name it `gb`.

b. Determine what happens when you reverse `roy` with `(reverse roy)`.

c. Determine what happens when you append the two lists together with `(append roy gb)`.

d. Determine what happens when you append the two lists together with `(append gb roy)`.

### Exercise 4: It's So `cons`-fusing

As you may recall, the `cons` procedure takes two parameters, a value and a list. It builds a new list by prepending the value to another list. However, it is also possible to apply `cons` to two non-list values. (You should not regularly do so at this point in your career, but some accidentally apply `cons` in this different way, so we want you to see what happens.)

Consider the following:

```(define one-two (cons 1 2))
(define won-too (list 1 2))
(define want-to (cons 1 (cons 2 null)))
```

a. Enter these definitions in the interactions pane of your work window and then ask for the values of `one-two`, `won-too`, and `want-to`. Explain how they are and are not similar.

b. What do you expect to have happen when you apply the `list?` predicate to each value? Check your answer experimentally.

c. What do you expect to have happen when you call `reverse` on each? Check your answer experimentally.

d. What do you expect to have happen if you try to get the `car` and the `cdr` of each of these values? Check your answer experimentally.

e. What do you expect to have happen if you append the list ```(3 4)``` to each of these values, as in the following example?

````>` `(append one-two (list 3 4))`
`?`
`>` `(append won-too (list 3 4))`
`?`
`>` `(append want-to (list 3 4))`
`?`
```

f. What do you expect to have happen if you append each of these values to the list `(0 0)`, as in the following example?

````>` `(append (list 0 0) one-two)`
`?`
`>` `(append (list 0 0) won-too)`
`?`
`>` `(append (list 0 0) want-to)`
`?`
```

If you are confused by any of the results, please look at the notes on this problem.

### Exercise 5: Fun with Stripes

Consider the following instructions.

```(define stripe-colors
(list RGB-RED RGB-YELLOW RGB-LIME RGB-AQUA RGB-BLUE))
(image-compute
(lambda (col row) (list-ref stripe-colors (modulo col 5)))
100 100)
```

a. What do you expect these instructions to do?

c. Extend that code to use seven colors instead of five. That is, you'll need to add two values to the list (presumably, by redefining the list) and use a different modulus.

d. As you should have observed, this makes a sequence of vertical stripes, each of width one pixel. We can make the stripes wider by computing the quotient of the column and the desired width. Try expanding your columns to a width of 5 and then 10. (Note that in order to use the result as a parameter to `modulo` and then in `list-ref`, we need to guarantee that it is an integer. Hence, you should compute the quotient with `quotient` rather than `/`.

e. Predict the result of the following instructions, and then try executing them.

```(define canvas (image-show (image-new 200 200)))
(region-compute-pixels!
canvas
100 0 100 100
(lambda (col row)
(list-ref stripe-colors (modulo (quotient col 10) 5))))
(region-compute-pixels!
canvas
0 100 100 100
(lambda (col row)
(list-ref stripe-colors (modulo (quotient row 10) 5))))
(region-compute-pixels!
canvas
100 100 100 100
(lambda (col row)
(list-ref stripe-colors
(modulo (quotient (+ row col) 10) 5))))
```

### Exercise 6: Generalized Stripe Drawing

In the previous exercise, you explored expressions that draw stripes. Now it's time to generalize those expressions.

a. Write a procedure, ```(diagonal-stripes colors stripe-width width height)```, that creates a `width`-by-`height` image with stripes of the specified width, using the colors in the list `colors` for the colors.

For example, if `colors` is ```(list RGB-RED RGB-GREY RGB-BLACK)```, the stripes will be red, grey, black, red, grey, black, red, grey, black, and so on and so forth.

b. Write a procedure, ```(cycling-stripes colors stripe-width width height)```, in which the stripes cycle from the first color to the last in the list, and then back again (and then forward again).

For example, if `colors` is ```(list RGB-RED RGB-PURPLE RGB-BLUE RGB-GREY)```, the stripes will be red, purple, blue, grey, blue, purple, red, purple, blue, grey, blue, purple, red, and so on and so forht.

### Exercise 7: Implementing Drawings

In the reading, we implemented simple shapes as heterogeneous lists with the kind of shape first, the color second, the x and y coordinates third and fourth, and the size fifth. The “drawings as values” model uses the same strategy, although with more elements.

````>` `drawing-unit-circle`
`(drawing ellipse 0 "" -0.5 -0.5 1 1)`
`>` `drawing-unit-circle`
`(drawing ellipse 0 "" -0.5 -0.5 1 1)`
`>` `(drawing-hscale (drawing-vscale drawing-unit-circle 10) 20)`
`(drawing ellipse 0 "" -10.0 -5.0 20 10)`
`>` `(drawing-hshift (drawing-vshift drawing-unit-square 30) 40)`
`(drawing rectangle 0 "" 39.5 29.5 1 1)`
`>` `(drawing-recolor drawing-unit-circle "red")`
`(drawing ellipse 16711680 "" -0.5 -0.5 1 1)`
`>` `(drawing-recolor drawing-unit-circle "yellow")`
`(drawing ellipse 16776960 "" -0.5 -0.5 1 1)`
```

As this example suggests, drawings of shapes are currently represented as eight element lists. The element 0 is always the symbol `drawing`. The element 1 is either the symbol `ellipse` or the symbol `rectangle`. Element 2 is the color (in the unreadable “RGB integer” format). Element 3 is the empty string and never seems to change. (In fact, it's something we used in an older implementation of drawings, and has just refused to leave.) Element 4 is the left edge, element 5 is the top edge, element 6 is the width, and element 7 is the height.

As you may have discovered earlier, it's dangerous to rely on the internal representation when you write procedures. However, let's suppose for the moment that you were willing to do so.

Write and test a procedure, ```(drawing-make-ellipse left top width height)```, that creates a new, filled, black ellipse with the specified edges and size. Rather than starting with the unit circle and scaling and shifting it, your procedure should build the list that represents the drawing directly.

For example, the following should render a 20x10 black ellipse with a left edige of 5 and a top edge of 15.

````>` `(image-show (drawing->image (drawing-make-ellipse 5 15 20 10) 50 50))`
```

## For Those With Extra Time

### Extra 1: From Ellipses to Rectangles

In the reading, we saw that we could convert our simple diamond shapes to squares by building new lists that replace the symbol `diamond` with the symbol `square`. We might do something similar with the “drawings as values” model.

Write a procedure, `(rectangularize drawing)`, that checks if `drawing` is an ellipse and, if so, builds a rectangular drawing that has the same left edge, top edge, width, and height as the ellipse. (If `drawing` is not an ellipse, `rectangularize` should just return the drawing.)

For example, the following code should draw a black ellipse on a red rectangle of the same size.

````>` `(define d1 (drawing-ellipse 5 15 20 10))`
`>` `(define d2 (drawing-recolor (rectangularize d2)))`
`>` `(image-show (drawing->image (drawing-group d2 d1) 100 100))`
```

### Extra 2: Resizing Drawings

Some of you were unhappy with the `drawing-scale` procedure, since it not only scaled the drawing, but also scaled the left edge and top edge of the drawing.

Now that we know a bit about the internal representation, it may be easier to resize the drawing without also shifting it.

Write a procedure, ```(drawing-resize drawing scale)``` that creates a new drawing by multiplying the width and height by `scale`, but does not change the left or top edge of the drawing.

You can compare the results of `drawing-resize` and `drawing-scale` with the following code.

````>` `(define d1 (drawing-elllipse 5 15 20 10))`
`>` `(define d2 (drawing-recolor (drawing-scale d1 2) "red"))`
`>` `(define d3 (drawing-recolor (drawing-resize d1 d2) "blue"))`
`>` `(image-show (drawing->image (drawing-group d2 d3) 100 100))`
```

## Notes

### Notes on Exercise 4: It's So `cons`-fusing

As you might guess, `won-two` is the list `(1 2)`. As you might not have guessed, `one-two` is the value `(1 . 2)`. That value looks much like a list, but it has a period in the middle. The period is a signal to you that the value is not a list.

Since `one-two` is not a list, it is not possible to reverse it or to append it to another list.

However, like the typical implementation of `cons`, the typical implementation of `append` does not confirm that its second parameter is a list. And, like `cons`, when given a non-list as a second parameter, `append` returns a non-list. In this case, `append` returns `(0 0 1 . 2)`. Once again, the period indicates “hey, that's not a list”.

Why does Scheme permit these non-lists? Because they are a generalization of lists (or at least of the techniques by which we process lists). As we'll see later in the semester, these non-lists can be quite useful.

Copyright (c) 2007-9 Janet Davis, Matthew Kluber, Samuel A. Rebelsky, and Jerod Weinman. (Selected materials copyright by John David Stone and Henry Walker and used by permission.)

This material is based upon work partially supported by the National Science Foundation under Grant No. CCLI-0633090. Any opinions, findings, and conclusions or recommendations expressed in this material are those of the author(s) and do not necessarily reflect the views of the National Science Foundation.

This work is licensed under a Creative Commons Attribution-NonCommercial 2.5 License. To view a copy of this license, visit `http://creativecommons.org/licenses/by-nc/2.5/` or send a letter to Creative Commons, 543 Howard Street, 5th Floor, San Francisco, California, 94105, USA.