Quotes from here or elsewhere in Simply Scheme unless otherwise specified. Refers to “the book” or “SS’ are to Simply Scheme.
The Quote Procedure
When you want to return words and not values you can use quote
. E.g. If you want to return +
as a character and not try to add stuff, you can do (quote +)
'
is actually short for quote
. Given that, you can’t use '
as an ordinary punctuation mark in a sentence (at least without putting the word in double-quote marks, which the book mentions in a footnote).
Selectors
Selectors are things that let you take apart words and sentences. Stuff like first
, last
, butfirst
, and butlast
.
We can use these primitive selectors to define other selectors like second
.
1
2
3
|
(define (second thing)
(first (butfirst thing)))
|
We can also use item
to directly select any arbitrary letter in a word or word in a sentence.
1
2
3
4
5
6
|
> (item 4 '(being for the benefit of mister kite!))
BENEFIT
> (item 4 'benefit)
E
|
The book notes that sentences containing exactly one word are different than a word itself. Because selectors operate on words at a character-level and sentences on a word level, this leads to different behaviors:
1
2
3
4
5
6
7
8
9
10
11
12
|
> (first 'because)
B
> (first '(because))
BECAUSE
> (butfirst 'because)
ECAUSE
> (butfirst '(because))
()
|
In the first example, first
is getting the first letter of the word because
. In the second example, first
is getting the first word of the sentence (because)
, and that sentence happens to only have one word. Similar result with butfirst
. The last example shows butfirst
returning an empty sentence.
The book notes that sometimes butfirst
will return a word with double-quotes around it, for example:
This indicates that the number is not being displayed in its normal form (as a number) but as a string – as a series of characters that you can chop up with selectors just like you can with the words “apple” or “potato”. Such a chopping up is in fact what happened here, with butfirst
returning all but the first character of 1024
.
bf
and bl
are abbreviations for butfirst
and butlast
respectively.
Constructors
Functions that put stuff together are called constructors
. word
and sentence
are examples of constructors. word
joins words and puts them together into a big word. sentence
can join both words and sentences together into a sentence with spaces in between the arguments. se
is an abbreviation for sentence
.
Self-Evaluating Numbers
The book asks of the following example:
1
2
3
|
> (se '(one plus one) 'makes 2)
(ONE PLUS ONE MAKES 2)
|
By the way, why did we have to quote
makes
in the last example, but not2
? It’s because numbers are self-evaluating, as we said in Chapter 3. We have to quotemakes
because otherwise Scheme would look for something namedmakes
instead of using the word itself. But numbers can’t be the names of things; they represent themselves. (In fact, you could quote the2
and it wouldn’t make any difference-do you see why?)
In chapter 3 the book said:
It’s easy to understand an expression that just contains one number. Numbers are self-evaluating; that is, when you evaluate a number, you just get the same number back.
I had a doubt as to whether I understood the idea that numbers are self-evaluating. Putting my doubt in the form of a question, I might ask: “What does it mean to say that numbers are self-evaluating?”
My attempt to think this through:
With words (or even just a letter) there is the possibility oft the word being used to evaluate something else, like with first
. So if you want to return just the word “first”, and not invoke the procedure first
, you have to give Scheme that information somehow (such as by using quote
or the abbreviation '
).
With numbers there is no such ambiguity. Numbers are an end in themselves – they always return themselves. They can never be used as something which evaluates something else. I actually tried to define a procedure 5
that would take a number and add 5
, just as a test, and got back an error:
First-Class Words and Sentences
SS gives some computing history and comparison to other languages. SS notes that other languages often treat sentences as being merely a collection of characters. Historically, computers dealt with just numbers. Instructions in the computer’s native machine language dealt with numbers, so programmers developed an attitude that numbers are the “real things” that computers deal with. Computers represent text characters as numbers, so in many programming languages individual characters are the “real things” but words or sentences are just collections of characters.
Scheme treats sentences as first-class data. The book authors believe that programming languages should let you express ideas in terms that match your thinking, and that seems reasonable. Sentences being first class data “means that a sentence, for example, can be an argument to a procedure; it can be the value returned by a procedure; we can give it a name; and we can build aggregates whose elements are sentences.”
Pitfalls
Things Not to Do
Things to avoid in words and sentences (assuming you’re not using double quotes): apostrophes, periods, commas, semicolons, quotation marks, vertical bars, parentheses.
Things that are okay to use in words and sentences: question marks and exclamation points.
Be careful not to use word
and sentence
as formal parameters. If you do so, you won’t be able to use the corresponding procedures for those terms in your definition:
1
2
3
4
5
6
|
(define (plural word) ;; wrong!
(word word 's))
> (plural 'george)
ERROR: GEORGE isn't a procedure
|
The result of substitution was not, as you might think,
1
2
|
(word 'george 's)
|
but rather
1
2
|
('george 'george 's)
|
When you provide the argument george
to your plural
function, it substitutes george
in for every instance of word
. You only intended the argument to be substituted in for the second instance of word
and wanted the first instance to be the procedure word, but Scheme doesn’t know that, so your program doesn’t work. The book says:
We’ve been using
wd
andsent
as formal parameters instead ofword
andsentence
, and we recommend that practice.
Other Pitfalls
There’s a difference between a word and a single-word sentence. For example, people often fall into the trap of thinking that the
butfirst
of a two-word sentence such as(sexy sadie)
is the second word, but it’s not. It’s a one-word-long sentence. For example, itscount
is one, not five.[3]
This seems connected to the idea of sentences being considered first class in Scheme. Since sentences are able to be dealt with as an object, they can have their own sentence-level attributes, like a count
that consists of something besides just the number of characters that the sentence consists of.
SS says not to worry if sometimes your procedure has quote-marks around it.
Exercises
β β Exercise 5.1 (Beginning of “Boring Exercises”)
What values are printed when you type these expressions to Scheme? (Figure it out in your head before you try it on the computer.)
This whole exercise was a good illustration of how low-level misunderstandings can lead to various errors. It’s good to correct such misunderstandings early on with simple examples like these.
β 5.1.1
1
2
|
(sentence 'I '(me mine))
|
This prints:
1
2
|
'(I me mine)
|
β 5.1.2
1
2
|
(sentence '() '(is empty))
|
I predict that this will print…
1
2
|
'(is empty))
|
…on the theory that since the first argument is an empty sentence, it’s basically a nullity and will get ignored by sentence
when doing the combination.
Yep, I was right.
β 5.1.3
1
2
|
(word '23 '45)
|
I predict this will print either ‘2345 or maybe “‘2345”
It actually just printed
1
2
|
2345
|
with no '
.
EDIT: The 2345
appears to be a number, not a string, even though it got put together into a word. You can do arithmetic operations on the result of (word '23 '45)
like +
and /
.
If I just type in 'apple
it returns with a '
in front. If I use word
on two words:
1
2
|
(word 'potato 'tomato)
|
then I get back 'potatotomato
. But numbers lack the '
in front. Interesting.
β 5.1.4
1
2
|
(se '23 '45)
|
So I’d expect either (23 45)
or '(23 45)
.
It was '(23 45)
.
β 5.1.5
1
2
|
(bf 'a)
|
I guess that this will print ""
.
It actually printed:
β 5.1.6
1
2
|
(bf '(aye))
|
I guess that this will print '()
I was correct.
β 5.1.7
1
2
|
(count (first '(maggie mae)))
|
β ERRONEOUS, SEE CORRECTION BELOW: This is similar to an example in the book. first
should return a one-word long sentence consisting of the first word of (maggie mae)
, namely, (maggie)
. count
should treat the value returned from first
as a sentence and thus count the number of words that make up that sentence (only one word in this case). so the value of the whole expression should be 1.
β CORRECTION: Ok so I had a misconception here. Earlier in my notes I actually have a relevant example:
1
2
3
|
> (first '(because))
BECAUSE
|
So first
actually does “reach into” the sentence to pluck out a word. So does last by the way:
1
2
3
|
> (last '(because))
'because
|
butfirst
and butlast
work differently:
1
2
3
4
5
6
7
8
9
|
> (butfirst '(because))
'()
> (butlast '(because))
'()
> (butfirst '(potato because))
'(because)
> (butlast '(potato because))
'(potato)
|
I think this all makes sense. first
basically gives you a specific location to go to (the first location in a sentence) to find a word to grab. butfirst
says to grab everything but that first word, including the “sentence bag” that the words are in (my own very sophisticated analogy π ). And if there’s only one on something you do butfirst
on, you disregard that one word but still grab the “sentence bag”.
Sentences are first class objects in Scheme, but you can still absolutely look “inside them” and pull stuff out if that’s what you want to do. And that’s what first
does. So the actual count
for this example is 6
, because count
is counting up the number of characters in the word “maggie”.
β 5.1.8
1
2
|
(se "" '() "" '())
|
I think this will return a single empty list '()
cuz it’s just joining a bunch of empty stuff together. (I figure that the “” are empty strings)
Wrong again π
The double quotes were joined together in a sentence.
β 5.1.9
1
2
|
(count (se "" '() "" '()))
|
Based on the return from the last example, I guess that this will return 5 – one for each double quote in the sentence plus one for the space in between.
Whoops. I think cuz this sentence was kind of weird, I thought of the count in terms of characters of a word instead of parts of a sentence. The answer makes sense to me though – I guess it’s counting each empty string as a part of the sentence.
If you do count
directly on an empty string you get 0. However, if you do count
on a single empty string in a sentence, you get 1.
β Exercise 5.2
For each of the following examples, write a procedure of two arguments that, when applied to the sample arguments, returns the sample result. Your procedures may not include any quoted data.
β 5.2.1
1
2
3
|
> (f1 '(a b c) '(d e f))
(B C D E)
|
Answer:
1
2
3
|
(define (f1 arg1 arg2)
(sentence (bf arg1)(bl arg2)))
|
β 5.2.2
1
2
3
|
(f2 '(a b c) '(d e f))
(B C D E AF)
|
Answer:
1
2
3
|
(define (f2 arg1 arg2)
(sentence (bf arg1)(bl arg2)(word (first arg1)(last arg2))))
|
β 5.2.3
1
2
3
|
> (f3 '(a b c) '(d e f))
(A B C A B C)
|
Answer:
1
2
3
|
(define (f3 arg1 arg2)
(sentence arg1 arg1))
|
β 5.2.4
1
2
3
|
> (f4 '(a b c) '(d e f))
BE
|
I solved this one two ways:
1
2
3
4
5
6
7
8
9
10
11
|
(define (f4 arg1 arg2)
(word
(first (bf arg1))
(first (bf arg2))
))
(define (f4b arg1 arg2)
(word
(item 2 arg1)
(item 2 arg2)))
|
β Exercise 5.3
Explain the difference in meaning between
(first 'mezzanine)
and(first '(mezzanine))
.
1
2
3
4
5
|
> (first 'mezzanine)
'm
> (first '(mezzanine))
'mezzanine
|
When presented with a word, first
returns the first character of the word – in the case of mezzanine, that means returning m
.
When presented with a sentence, first
returns the first word of the sentence as a word (and not as a sentence) – in the case of '(mezzanine)
, that means returning mezzanine
.
β Exercise 5.4
Explain the difference between the two expressions
(first (square 7))
and(first '(square 7))
.
1
2
3
4
5
6
|
> (first (square 7))
4
> (first '(square 7))
'square
|
(first (square 7))
says to return the first character from the result of running the procedure square
on the number 7
. The result of (square 7)
is the two-digit sequence 49
. The first character of 49
is 4
. Note that this 4
is returned as an actual number that you can do arithmetic with.
(first '(square 7))
says to return the first word of a two-word sentence (square 7)
, which is square
.
β Exercise 5.5
Explain the difference between
(word 'a 'b 'c)
and(se 'a 'b 'c)
.
1
2
3
4
5
6
|
> (word 'a 'b 'c)
'abc
> (se 'a 'b 'c)
'(a b c)
>
|
(word 'a 'b 'c)
joins its arguments as three letters in a single word. (se 'a 'b 'c)
joins its arguments as three words in a single sentence.
β Exercise 5.6
Explain the difference between
(bf 'zabadak)
and(butfirst 'zabadak)
.
1
2
3
4
5
|
> (bf 'zabadak)
'abadak
> (butfirst 'zabadak)
'abadak
|
These have the same meaning – bf
is just an abbreviation for butfirst
.
β Exercise 5.7
Explain the difference between
(bf 'x)
and(butfirst '(x))
.
1
2
3
4
5
|
> (bf 'x)
'||
> (butfirst '(x))
'()
|
(bf 'x)
gets all but the first character from the word x
. Since x
just has one character, an empty word is returned, and Scheme sometimes apparnently does this in the form of ||Β
.
(butfirst '(x))
returns all but the first word from the sentence (x)
. Since (x)
only has one word, what is returned is the empty sentence, ()
.
β Exercise 5.8
Which of the following are legal Scheme sentences?
1
2
3
4
5
|
(here, there and everywhere)
(help!)
(all i've got to do)
(you know my name (look up the number))
|
only (help)
is legal. (here, there and everywhere)
has a prohibited (for the sentence context) comma, (all i've got to do)
has a prohibited apostrophe, and (you know my name (look up the number))
has prohibited inner parentheses.
β Exercise 5.9
Figure out what values each of the following will return before you try them on the computer:
β 5.9.1
1
2
3
4
5
|
(se (word (bl (bl (first '(make a))))
(bf (bf (last '(baseball mitt)))))
(word (first 'with) (bl (bl (bl (bl 'rigidly))))
(first 'held) (first (bf 'stitches))))
|
This returns a sentence made up of two words, (matt wright)
.
β 5.9.2
1
2
3
4
|
(se (word (bl (bl 'bring)) 'a (last 'clean))
(word (bl (last '(baseball hat))) (last 'for) (bl (bl 'very))
(last (first '(sunny days)))))
|
This returns a sentence made up of two words, (brian harvey)
.
β Exercise 5.10
What kinds of argument can you give
butfirst
so that it returns a word? A sentence?
butfirst
will return a word if you give it a word or give it a sub-expression that returns a word. if you give it a one character word, it will return the empty word.
butfirst
will return a sentence if you give it a sentence or a sub-expression that returns a sentence. if you give it a one word sentence, it will return an empty sentence.
β Exercise 5.11
What kinds of argument can you give
last
so that it returns a word? A sentence?
last
will return a word (a single character) if you give it a word. If you give it a single character, it will return that same character. last
also returns a word if you give it a sentence. in that case, it returns the last word of the sentence.
last
will return as sentence if you give it a nested sentence, as in:
1
2
3
|
> (last '((potato ninja)))
'(potato ninja)
|
β Exercise 5.12
Which of the functions
first
,last
,butfirst
, andbutlast
can return an empty word? For what arguments? What about returning an empty sentence?
butfirst
– if you give it a one character word, it will return the empty word.
butfirst
– if you give it a one word sentence, it will return an empty sentence.
butlast
– if you give it a one character word, it will return the empty word.
butlast
– if you give it a one word sentence, it will return an empty sentence.
last
– could not figure out how to get it to return empty word or empty sentence.
first
– – could not figure out how to get it to return empty word or empty sentence.
If you try to give last
or first
an empty sentence, it gives an error on my Scheme.
π€Exercise 5.13 (Beginning of “Real Exercises”)
What does
'
β'banana
stand for?
If I enter this into Scheme I get the following:
It looks to me like the space is ignored, so the result is a word. My first guess was maybe that it stands for a 7 character word – banana preceded by a '
being treated as just a character. In light of the below, I think it may actually stand for a word quotebanana
, and '
is just representing that in abbreviated form. Not sure.
If you put a stray '
anywhere else in a word other than as the first character, you’d get an error. But maybe if the '
literally follows the first '
then that escapes the second '
somehow, not sure.
What is
(first '
β'banana)
and why?
I get:
If I do (first ' +banana)
I get:
So maybe it is just returning the name of the procedure as a character if that character happens to serve as the first character of a word. And for most single character procedures that single character is their name, but '
is actually short for quote
, so we get the full name when we use first
to pull '
.
β Exercise 5.14
Write a procedure
third
that selects the third letter of a word (or the third word of a sentence).
Answer:
1
2
3
|
(define (third arg)
(first (butfirst (butfirst arg))))
|
β Exercise 5.15
Write a procedure first-two
that takes a word as its argument, returning a two-letter word containing the first two letters of the argument.
1
2
3
|
> (first-two 'ambulatory)
AM
|
Answer:
1
2
3
|
(define (first-two word-arg)
(word (first word-arg) (first (bf word-arg))))
|
β Exercise 5.16
Write a procedure
two-first
that takes two words as arguments, returning a two-letter word containing the first letters of the two arguments.
1
2
3
|
> (two-first 'brian 'epstein)
BE
|
Answer:
1
2
3
|
(define (two-first word-arg1 word-arg2)
(word (first word-arg1)(first word-arg2)))
|
Now write a procedure
two-first-sent
that takes a two-word sentence as argument, returning a two-letter word containing the first letters of the two words.
1
2
3
|
> (two-first-sent '(brian epstein))
BE
|
Answer:
1
2
3
|
(define (two-first-sent sent-arg)
(word (first (first sent-arg))(first (last sent-arg))))
|
β Exercise 5.17
Write a procedure
knight
that takes a person’s name as its argument and returns the name with “Sir” in front of it.
1
2
3
|
(define (knight name)
(se 'sir name))
|
β Exercise 5.18
Try the following and explain the result:
1
2
3
|
(define (ends word)
(word (first word) (last word)))
|
(ends ‘john)
As written, the argument john
winds up getting substituted for all the copies of word
in the body, and john
isn’t a procedure, so the program gives an error.
Fixed version:
1
2
3
|
(define (ends wd)
(word (first wd) (last wd)))
|
β Exercise 5.19
Write a procedure
insert-and
that takes a sentence of items and returns a new sentence with an “and” in the right place:
1
2
|
> (insert-and '(john bill wayne fred joey))(JOHN BILL WAYNE FRED AND JOEY)
|
Answer:
1
2
3
|
(define (insert-and input-sent)
(se (butlast input-sent) 'and (last input-sent)))
|
β Exercise 5.20
Define a procedure to find somebody’s middle names:
1
2
3
4
5
6
7
8
9
|
> (middle-names '(james paul mccartney))
(PAUL)
> (middle-names '(john ronald raoul tolkien))
(RONALD RAOUL)
> (middle-names '(bugs bunny))
()
> (middle-names '(peter blair denis bernard noone))
(BLAIR DENIS BERNARD)
|
Answer:
1
2
3
|
(define (middle-names name)
(bf (bl name)))
|
β Exercise 5.21
Write a procedure
query
that turns a statement into a question by swapping the first two words and adding a question mark to the last word:
1
2
3
4
5
6
|
> (query '(you are experienced))
(ARE YOU EXPERIENCED?)
> (query '(i should have known better))
(SHOULD I HAVE KNOWN BETTER?)
|
Two solutions:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
(define (query sent-arg)
(se (first (butfirst sent-arg))
(first sent-arg)
(butfirst (butfirst (butlast sent-arg)))
(word (last sent-arg) '?)))
(define (query-item sent-arg)
(se (item 2 sent-arg)
(item 1 sent-arg)
(butfirst (butfirst (butlast sent-arg)))
(word (last sent-arg) '?)))
|
End of Chapter Notes
This chapter went really smoothly. Wasn’t sure about Exercise 5.13 but just skipped it and doubled-back later.
Am I asking enough questions? I noticed that AnneB asked and highlighted this question on her blog: “Unanswered question: What does an output of two vertical lines (||)
mean and how is it different from two double quote marks?” I had that same question but didn’t explicitly ask it.
Consider using shorter parameter names.
Consider emphasizing testing stuff more and paraphrasing the book less.