Skip to main content

Laboratory: Basic types

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, and symbols.

Useful procedures and notation

Numbers

Numeric type predicates: exact?, inexact?, integer?, real?, rational?, complex?

Characters

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, and 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>?.

Strings

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>?

Preparation

a. 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 and the reading on numeric values.

Exercises

Exercise 1: Simple numeric computation

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.

Exercise 2: Bounds

Suppose that we’ve defined val as a number, lower as 0, and upper as 100. Consider the following definition.

(define bounded-val (min (max val lower) upper))

a. Suppose val is 25. What value will this definition associate with bounded-val? That is, what result do you expect to get when you type the following in the definitions pane, click Run, and then enter bounded-val in the interactions pane?

(define val 25)
(define lower 0)
(define upper 100)
(define bounded-val (min (max val lower) upper))

b. Check your answer experimentally.

c. Suppose val is 211. What value will this definition associate with bounded-val? That is, suppose you replace (define val 25) with (define val 211), click Run, and then type bounded-val

d. Check you answer experimentally.

e. Suppose val is -25. What value will this definition associate with bounded-val?

f. Explain, in your own words, what the definition computes when lower is 0 and upper is 100.

g. Suppose we redefined lower to -10 and upper to 10 and then redid each of a-e. What results would we get?

h. Explain, in your own words, what this definition computes in terms of lower and upper.

Exercise 3: Remainder

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.

Exercise 4: From reals to integers

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.

Exercise 5: Exploring rational numbers

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.

Exercise 6: Large Numbers

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.

Exercise 7: Complex numbers

We’ve seen that Scheme provides integers, rationals, reals, exact, and inexact numbers, many think that these are more kinds of numbers than you would ever need. But, believe it or not, it provides even more.

What value do you think Racket will give for (sqrt -4)?

Check your answer experimentally.

Although you may have been told at one time that “negative numbers don’t have square roots”, that’s only true if we restrict ourselves to real roots. As you’ve just discovered, Racket supports “complex numbers”, which have not only a real component, but also an imaginary component represented by i, the square root of negative 1. Complex numbers have many uses, including representing points on the plane. We may revisit them later this semester. For now, we’re just introducing them to help you understand the depth of Scheme (and to warn you that you will sometimes get answers when you expect errors.

Exercise 8: String basics

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?

Exercise 9: Creating questions

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.

Exercise 10: Substrings

Consider the string "Department".

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.

Exercise 11: Referencing lengths

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?

Exercise 12: A simple form letter

Consider the following definitions:

(define recipient "NAME")
(define magazine "NAME")
(define article "NAME")
(define cr (string #\newline))

(define letter
 (string-append
  "Dear " recipient ", " cr
  cr
  "Thank you for your submission to " magazine ".  Unfortunately, we " cr
  "consider the subject of your article, " article ", inappropriate " cr
  "for our readership.  In fact, it is probably inappropriate for any " cr
  "readership.  Please do not contact us again, and do not bother " cr  
  "other magazines with this inappropriate material or we will be " cr
  "forced to contact the appropriate authorities." cr
  cr
  "Regards," cr
  "Ed I. Tor" cr)))

a. Suppose we define recipient as "Professor Schneider", magazine as "College Trustee News", and article as “Using Grinnell’s Endowment to Eliminate Tuition”. What value do you expect letter` to have?

b. Check your answer experimentally.

c. What do you expect the output of the following expression to be?

> (display letter)

d. Check your answer experimentally.

Exercise 13: Adding quotation marks

a. What changes are necessary to letter so that name of the article appears in quotation marks?

b. Check your answer experimentally.

For Those with Extra Time

Extra 1: Rounding, revisited

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.

Extra 2: Rounding, re-revisited

In a problem above, you wrote instructions for rounding a real number to two digits after the decimal place. While such rounding is useful, it is even more useful to be able to round to an arbitrary number of digits after the decimal point.

Suppose precision is a non-negative integer and val is a real value. Write instructions for rounding val to use only precision digits after the decimal point.

> (your-instructions ... val ... precision ...)

As you write your instructions, you may find the expt function useful. (expt b p) computes bp.

Notes

Notes on Exercise 4: From reals to integers

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.

Return to the problem

Notes on Exercise 5: Exploring rational numbers

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 252. (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.

Return to the problem.