- Held
- Monday, 4 February 2019
- Writeup due
- Wednesday, 6 February 2019
- Summary
- We explore some of the basic types that many implementations of Scheme, including Racket, support. These include a variety of numeric types, characters, strings, symbols, and lists.

Basic numeric operations: `+`

, `-`

, `*`

, `/`

, `quotient`

, `remainder`

,
`expt`

.

Numeric conversion: `exact->inexact`

, `inexact->exact`

, `floor`

,
`ceiling`

, `round`

, `truncate`

.

Numeric type predicates: `exact?`

, `inexact?`

, `integer?`

, `real?`

,
`rational?`

, `complex?`

Constant notation: `#\ch`

(character constants)

Character constants: `#\a`

(lowercase a) … `#\z`

(lowercase z); `#\A`

(uppercase A) … `#\Z`

(uppercase Z); `#\0`

(zero) … `#\9`

(nine);
`#\space`

(space); `#\newline`

(newline); and `#\?`

(question mark).

Character conversion: `char->integer`

, `integer->char`

, `char-downcase`

, `char-upcase`

Character predicates: `char?`

, `char-alphabetic?`

, `char-numeric?`

,
`char-lower-case?`

, `char-upper-case?`

, `char-whitespace?`

Character comparison: `char<?`

, `char<=?`

, `char=?`

, `char>=?`

, `char>?`

,
`char-ci<?`

, `char-ci<=?`

, `char-ci=?`

, `char-ci>=?`

, and `char-ci>?`

.

Constant notation: `"string"`

(string constants).

String predicates: `string?`

String constructors: `make-string`

, `string`

, `string-append`

String extractors: `string-ref`

, `substring`

String conversion: `number->string`

, `string->number`

, `symbol->string`

,
`string->number`

String analysis: `string-length`

String comparison: `string<?`

, `string<=?`

, `string=?`

, `string>=?`

, `string>?`

, `string-ci<?`

, `string-ci<=?`

, `string-ci=?`

, `string-ci>=?`

, `string-ci>?`

Constant notation: `'(val val val)`

List operations: `take`

, `drop`

, `list-ref`

, `length`

a. Open a terminal window and type `/home/rebelsky/bin/csc151/update`

to
make sure that you have the latest version of the class software.

b. If you have not done so already, you may also want to open separate tabs in your Web browser with the reading on characters and strings, the reading on numeric values, the reading on symbols, the reading on list basics, and the reading on text files.

c. Don’t forget to put `(require loudhum)`

in the definitions pane.

a. Determine what type DrRacket gives for the square root of two, computed
by `(sqrt 2)`

. Is it exact or inexact? Real? Rational? An integer?

b. How do we know that the answer it gives us is correct? (What does “correct” mean when the answer is irrational?) We could check by squaring the value, as in

```
> (* (sqrt 2) (sqrt 2))
```

Better yet, we could subtract that result from 2, as in

```
> (- 2 (* (sqrt 2) (sqrt 2)))
```

c. What do the results of these experiments suggest? Why do you think you got the answer you got?

d. Do you expect to have the same problem as in the previous exercise if you compute the square root of 4 rather than the square root of 2? Why or why not?

e. Check your answer experimentally.

As the reading suggests, the `remainder`

procedure computes the amount “left over” after you divide one number by another. The reading suggests that `remainder`

provides an interesting alternative to using `max`

and `min`

to limit the values of functions.

a. What value do you expect each of the following to produce? *Write down answers! Do not just type the code into DrRacket.*

```
> (remainder 8 3)
> (remainder 3 8)
> (remainder 8 8)
> (remainder 9 8)
> (remainder 16 8)
> (remainder 827 8)
> (remainder 0 8)
> (remainder -8 8)
> (remainder -7 8)
> (remainder -9 8)
> (remainder -1 8)
```

b. Check your answers experimentally, one at a time. If you find that any of your answers don’t match what Scheme does, try to figure out why (asking your professor or a tutor if you need help), and then rethink your remaining answers before checking them experimentally.

As the reading on numbers suggests, Scheme provides
four functions that convert real numbers to nearby integers: `floor`

,
`ceiling`

, `round`

, and `truncate`

. The reading also claims that there
are differences between all four.

To the best of your ability, figure out what each does, and what distinguishes it from the other three. In your tests, you should try both positive and negative numbers, numbers close to integers and numbers far from integers. (Numbers whose fractional part is 0.5 are about as far from an integer as any real number can be.)

Once you have figured out answers, check the notes on this problem.

DrRacket’s implementation of Scheme permits you to treat any real number as a rational number, which means we can get the numerator and denominator of any real number. Let’s explore what numerator and denominator that implementation uses for a variety of values.

a. Determine the numerator and denominator of the rational representation of the square root of 2.

b. Determine the numerator and denominator of the rational representation of 1.5.

c. Determine the numerator and denominator of the rational representation of 1.2.

d. Determine the numerator and denominator of 6/5.

If you are puzzled by some of the later answers, you may want to read the notes on this problem. Note that we will not expect you to regularly figure out these strange numerators and denominators.

Many programming languages have limits on the size of the numbers they represent. In some cases, if the number is large enough, they approximate it. In other cases, if the number is large enough, the calculations you do with the error are erroneous. (You’ll learn why in a subsequent course.) And in still others, the language treats large enough values as the special value “infinity”.

See what happens if you try to have DrRacket compute with some very large exact integers. You may find the `expt`

function helpful. Then see what happens if you try convert those integers to inexact values. Here are two examples to start with, but you should try more.

```
> (define x (expt 2 100))
> (define ex (exact->inexact x))
```

See what happens if you try to have DrRacket compute with some very small exact rational numbers (say, 1 divided by one of those large numbers). Then see what happens if you convert those rational numbers to inexact values.

*A work in process.*

a. Using `char->integer`

, Find the collating sequence number for
`#\a`

, `#\A`

, `#\z`

, `#\Z`

, and `#\space`

.

b. Using `integer->char`

, find the character that corresponds to
numbers 32, 88, 223, and 8501.

c. Write a procedure, `(next-char char)`

that takes as input a
character and returns the next character in the collating sequence.

```
> (next-char #\a)
#\b
```

a. Write a Scheme expression to determine whether the symbol `'plaid`

is a string.

b. Write a Scheme expression to determine whether the character `#\A`

is a string.

c. Does the empty string (represented as `""`

) count as a string?

Develop three ways of constructing the string `"???"`

: one using a call to
`make-string`

, one a call to `string`

, and one a call to `list->string`

.

Consider the string `"Department"`

. Using a the `substring`

procedure, we can extract a wide variety
of words from this one string. Write a Scheme expression to extract each of the requested words
below. You may use `substring`

multiple times in combination with `string-append`

, but please do not
use string constants (e.g. `"apart"`

), characters, or any other procedures.

a. Write an expression to extract the string `"Depart"`

from `"Department"`

.

b. Write an expression to extract the string `"part"`

from `"Department"`

.

c. Write an expresssion to extract the string `"ment"`

from `"Department"`

.

d. Write an expression to extract the string `"a"`

from `"Department"`

.

e. Write an expression to extract the empty string from `"Department"`

.

f. Write an expression to extract the string `"Dent"`

from `"Department"`

. Note that you may need to use two calls to `substring`

along with a call to `string-append`

.

g. Write an expression to extract the string `"apartment"`

from `"Department"`

. Once again, you may need multiple calls.

Here are two opposing views about the relationship between `string-length`

and `string-ref`

:

- “No matter what string
`str`

is, provided that it’s not the empty string,`(string-ref str (string-length str))`

will return the last character in the string.” - “No matter what string
`str`

is,`(string-ref str (string-length str))`

is an error.”

Which, if either, of these views is correct? Why?

As you may recall, the `string-split`

procedure breaks a string
up into a list of strings.

```
> (string-split "once upon a time" " ")
'("once" "upon" "a" "time")
> (string-split "a one and a two and a three" "and")
'("a one " " a two " " a three")
> (string-split "a one and a two and a three" " and ")
'("a one" "a two" "a three")
```

a. What type of value does `string-split`

return?

b. Determine experimentally what happens if you do not provide a
second argument to `string-split`

.

c. What do you expect to happen if the string you split a string that contains non-alphanumeric characters and do not provide a second argument? E.g.,

```
> (string-split "CSC 151 (a.k.a. Functional Problem Solving) is func-y.")
```

d. Check your previous answer experimentally

e. What do you expect to happen if the second argument to `string-split`

does not appear in the first string?

f. Check your previous answer experimentally.

Consider the following definitions, which you should add to your definitions pane.

```
(define paragraph "There was no possibility of taking a walk that day. We had been wandering, indeed, in the leafless shrubbery an hour in the morning; but since dinner (Mrs. Reed, when there was no company, dined early) the cold winter wind had brought with it clouds so sombre, and a rain so penetrating, that further out-door exercise was now out of the question.")
(define words (string-split paragraph))
```

a. As you may recall, `(take lst n)`

grabs the first `n`

elements of `lst`

(prounounced “list”) and `(drop lst n)`

drops the first `n`

elements of
`lst`

.

What results do you expect for each of the following expressions?

```
> words
?
> (take words 5)
?
> (drop words 5)
?
> (take (drop words 4) 6)
?
```

b. Check your answers experimentally.

c. As you may recall `(list-ref lst n)`

, grabs element `n`

of a list.

What results do you expect for each of the following expressions?

```
> (list-ref words 2)
?
> (list-ref words 4)
?
> (list-ref words (- (length words) 2))
?
> (list-ref words (length words))
?
```

d. Check your answers experimentally.

e. As you may recall, the `(reverse lst)`

procedure takes a list
as input and returns the list in the opposite order. What results
do you expect for each of the following expressions?

```
> (take (reverse words) 5)
?
> (reverse (take (reverse words) 5))
?
```

f. Check your answers experimentally.

g. As you may recall, the `(index-of lst val)`

procedure takes a
list and a value as parameters and returns the first index of the
word in that list.

What results do you expect for each of the following expressions?

```
> (index-of words "possibility")
?
> (index-of words "no")
?
> (index-of words "Jabberwock")
?
> (index-of words "there")
?
> (index-of words "early")
?
```

h. Check your answers eperimentally.

As you’ve noted, the `take`

procedure grabs elements from the beginning
of a list. What if we wanted to grab elements from the end of a list?

a. Write a procedure, `(take-from-end lst n)`

, that returns a list
containing the last `n`

elements of lst. You may assume that the
list has at least `n`

elements.

```
> (take-from-end (list "a" "b" "c" "d" "e") 2)
'("d" "e")
> (take-from-end (list 2 3 5 7 11 13 17 19 23) 4)
'(13 17 19 23)
> (take-from-end (list "slithy" "toves" "gyre" "gimble") 0)
'()
```

b. There are two strategies that students commonly use when implementing
`take-from-end`

. Some use a combination of `take`

and `reverse`

. Some
use a combination of `drop`

and `length`

. Implement `take-from-end`

using whichever strategy you did not use. (If you used neither, choose
one.)

*If you find that you finish all of these problems early, try one
or more of the following problems.*

You may recall that we have a number of mechanisms for rounding real numbers to integers. But what if we want to round not to an integer, but to only two digits after the decimal point? Scheme does not include a built-in operation for doing that kind of rounding. Nonetheless, it is fairly straightforward.

Suppose we have a value, `val`

. Write instructions that give val rounded
to the nearest hundredth. For example,

```
> (define val 22.71256)
> (your-instructions val)
22.71
> (define val 10.7561)
> (your-instructions val)
10.76
```

Hint: You know how to round at the decimal point. Thik about ways to shift the decimal point.

You’ve found how to take elements from the front of a list and the back of a list. But what about the middle of a list?

Write a procedure, `(sublist lst a z)`

that creates a list
of the elements from indices `a`

to `z`

-1 in `lst`

.

Here are the ways we tend to think of the four functions:

`(floor r)`

finds the largest integer less than or equal to `r`

. Some would phrase this as “`floor`

rounds down”.

`(ceiling r)`

finds the smallest integer greater than or equal to `r`

. Some would phrase this as “`ceiling`

rounds up”.

`(truncate r)`

removes the fractional portion of `r`

, the portion after the decimal point.

`(round r)`

rounds `r`

to the nearest integer. It rounds up if the decimal portion is greater than 0.5 and it rounds down if the decimal portion is less than 0.5. If the decimal portion equals 0.5, it rounds toward the even number.

```
> (round 1.5)
2
> (round 2.5)
2
> (round 7.5)
8
> (round 8.5)
8
> (round -1.5)
-2
> (round -2.5)
-2
```

It’s pretty clear that `floor`

and `ceiling`

differ: If `r`

has a fractional component, then `(floor r)`

is one less than `(ceiling r)`

.

It’s also pretty clear that `round`

differs from all of them, since it can round in two different directions.

We can also tell that `truncate`

is different from `ceiling`

, at least for positive numbers, because `ceiling`

always rounds up, and removing the fractional portion of a positive number causes us to round down.

So, how do `truncate`

and `floor`

differ? As the previous paragraph implies, *they differ for negative numbers*. When you remove the fractional component of a negative number, you effectively round up. (After all, -2 is bigger than -2.2.) However, `floor`

always rounds down.

Why does Scheme include so many ways to convert reals to integers? Because experience suggests that if you leave any of them out, some programmer will need that precise conversion.

The underlying Scheme implementation seems to represent the fractional part of many numbers as the ratio of some number and 4503599627370496, which happens to be 2^{52}. (Most computers like powers of 2.) By using a large denominator, it helps ensure that representations are as accurate as possible.

If you are energetic, you might scour the Web to find out why they use an exponent of 52.

This laboratory is based on a similar laboratory from a prior version of CSC 151. It includes a few new problems on lists and files and eliminates a few problems on numeric values. The problem on text files is taken from a library on file input from a prior version of CSC 151.