Simply Scheme Chapter 6 Error Follow-up

I caught an error in my solution for Exercise 6.11 for Simply Scheme Chapter 6. I noticed that there didn’t seem to be the correct number of matching parentheses on one line. Once I corrected the error, the function started failing one of my tests. So the passing was just through happenstance. I’m going to put the parentheses error aside and focus on what I consider to be the basic logical mistake.

Here is the erroneous procedure with the parentheses that I intended:

For this procedure, (valid-date? 2 29 1964) returns false but i want it to return true. What’s the problem?

The problem is the manner in which I constructed the logic. If anything nested under the “or” returns true, then the whole February-related line of the cond will return false. So let’s run through the program with the example the input I’m having trouble with, 2 29 1963.

Since the day is = 29, (> day 29) returns false. So far so good.
Since the year is not divisible by 100, (and (= day 29)(divisible? year 100) (not (divisible? year 400)))Β  returns false.
Since the year is divisible by 4, (and (= day 29)(not (divisible? year 4))) returns false.
The day is > 29, though, so (and (> day 28))))) returns true. Uh-oh.

So what’s going wrong?

I think for this part of my program to make sense, all the things under the “or” have to be stuff that I never want to happen.

For Februaries, the number of days is never greater than 29. So (> day 29) is okay.

For Februaries, you can never have a situation where the number of days is 29, and the year is divisible by 100 but not 400, so (and (= day 29)(divisible? year 100) (not (divisible? year 400)))Β  is okay.

You can never have a situation where February has 29 days and the year isn’t divisible by 4 (some cases where the year is divisible by 4 and the date is still invalid exist, but those are covered by the rule in the last paragraph) . So (and (= day 29)(not (divisible? year 4))) is okay.

Re: (and (> day 28)), there are years that I want to return as valid even when they have more than 28 days in Febraury — specifically, the leap years. But this part of the program will be checked every time (valid-date?) is run, and so every leap year date will fail.

The (and (> day 28)) is actually introducing an entirely unnecessary error. The program already covers the prohibited cases for February. Days being equal to, for example, 30 is entirely prohibited under the rule that says days can never be more than 29, and days being equal to 29 is prohibited in the cases not allowed by the rules on leap years. So what’s left for (and (> day 28)) to do? Nothing except mess up my program!

Here is my fixed procedure:

Things to Do Better to Avoid This Kind of Mistake

  1. Break up tricky logical things into separate lines of a cond rather than trying to be elegant and getting myself confused.
  2. Carefully check each line of a program for parentheses issues when I’m done writing.
  3. Do more step by step logical analysis of programs using some example inputs and trees.
  4. If you’re gonna do “return false if X, else return true” style of organizing a program, consider expressly listing out every prohibited case and thinking about the logical relationships / Venn diagrams etc between the cases.

Simply Scheme Chapter 6 – True and False

Quotes from here or elsewhere in Simply Scheme unless otherwise specified. Refers to “the book” or “SS’ are to Simply Scheme.

Github here.

Sometimes I show past solutions from previous attempts through the book. Those are for comparison only – I’m not really testing those like I am my current solutions.

Predicates

Boolean values in scheme are #t for true and #f for false (and #true and #false also seem to work).

A function that returns either true or false is a predicate. Some examples:
equal?– checks if args are equal (works on numbers, sentences, procedures, words, booleans).
member? – checks if a letter is in a word or a word is in a sentence.
= – checks if numbers are equal.
> – checks if one number is greater than another. Similar functions are <, >=, and <=.
empty? – checks if for an empty sentence '() or string ""
number? – checks if an argument is a number.
boolean? – checks if an argument is a boolean.
word? – checks if an argument is a word.
sentence? – checks if an argument is a sentence.

You can also define your own predicates e.g.

The and, or, and not procedures, along with if, are useful to use in conjunction with predicates. The book gives some examples.

Special Forms

if, and, and or are special forms.

if doesn’t evaluate all its arguments. It only evaluates the one it needs to based on whether the first argument returns #t or not.

The rule is that if always evaluates its first argument. If the value of that argument is true, then if evaluates its second argument and returns its value. If the value of the first argument is false, then if evaluates its third argument and returns that value.

So in the above example, if evaluates the first argument, which is (= 3 3). If and only if that returns true does it evaluate and return the second argument 'sure. If and only if the first argument returns false does it evaluate (factorial 1000).

and and or are also special forms which evaluate their arguments from left to right. or stops and returns a true value as soon as it hits a true argument, and and stops and returns false as soon as it hits a false argument.

Semipredicates

SS says every value is considered true except #f. This fact allows us to have semipredicates. The book doesn’t actually formally define what a semipredicate is in this chapter. But I think that predicates are procedures that return either true or false, and semipredicates seem to be procedures that can return either false or a true value other than just#t or #true.

πŸ€” Integer-quotient and Some Confusion

There was a passage that I had some trouble understanding. This might be a bit rambly so maybe skip it if you’re just quickly skimming.

#T isn’t the only true value. In fact, every value is considered true except for #f.

This allows us to have semipredicates that give slightly more information than just true or false. For example, we can write an integer quotient procedure. That is to say, our procedure will divide its first argument by the second, but only if the first is evenly divisible by the second. If not, our procedure will return #f.

SS then gives the following example (i’ve added the divisible procedure below, which was defined earlier in the chapter, as necessary context)

So backing up, I thought that, in the part that says…

This allows us to have semipredicates that give slightly more information than just true or false.

…that the “this” referred to the fact that…

every value is considered true except for #f

…which I will refer to herein as the Truth-Fact. Based on that interpretation, I expected the Truth-Fact to be a necessary part of how the first version of integer-quotient works. I now think that maybe they were actually referring to the Truth-Fact being necessary for the revised version that they describe later in the section, though, but I’m not sure.

I read the procedure above this way: divisible is a necessary helper procedure. It relies on the = procedure, which returns #t if the remainder is 0 and #f if the remainder is something other than 0. The divisible? procedure called within the first argument of the if will return #t if the remainder of the first argument passed into integer-quotient is 0 when divided by the second argument. In that case, the check by the if procedure that its first argument is true will succeed, and the second argument will be evaluated and the quotient returned. If divisible? returns false, however, then the third argument to the if – the #f – will be returned.

With that description of the procedure in mind, I don’t see how the Truth-Fact plays a role in the version of integer-quotient above. I get that integer-quotient meets what I laid out as my definition of a semipredicate, but whether something is a semipredicate seems different than whether it relies on the Truth-Fact for its operation.

and and or also semipredicates. The book mentions that or will return the first true result:

3 has a truth value of #t. or doesn’t return that #t, but the value itself.

and works the following way:

If all the arguments given to and are true, it returns the value of the last argument.

Of the fact that and returns the value of the last argument when all the arguments given to and are true, the book says the following:

As an example in which this behavior is useful, we can rewrite integer-quotient more tersely:

With this example, I can easily see how the Truth-Fact is necessary to how it works. Specifically, the programmer is relying on the fact that the numeric value of (/ big little) will return as true (for the and) and return as the value that the procedure outputs. When the first argument to the and (the (divisible? big little)) is returned as true, the programmer wants the second argument to be the value that is returned by invocation the procedure. and will return the final value when both arguments are true, and so the number returned by (/ big little) being true is necessary for this function to work in the way the programmer wants it to.

Cond

cond provides a concise way of handling situations where you have to choose from among multiple possibilities.

To take one example, for ((equal? letter 'i) 1), (equal? letter 'i) is the condition that gets tested, and 1 is the thing that gets returned if the condition is true. So each cond clause like this is analogous to the first two arguments after an if clause. But with cond you get to have a whole series of alternatives rather than just specifying one like you can in if, and each alternative can have its own condition, unlike in if where you’re just testing the first argument.

cond is a special form and doesn’t evaluate arguments until it needs to.

Re: else:

By convention, the last argument always starts with the word else instead of an expression. You can think of this as representing a true value, but else doesn’t mean true in any other context; you’re only allowed to use it as the condition of the last clause of a cond.

The book emphasizes that one should put the most restrictive test first in a cond statement. Pasting this as images cuz of a formatting issue on the web page:


Why is (empty? sent) more restrictive than (number? (first sent))? I think because (empty? sent) will only return true on an empty sentence, whereas (number? (first sent)) will return true on infinitely many potential sentences. So (empty? sent) rules out all sentences but one, whereas (number? (first sent)) will return true for many sentences. Another way of saying it is that (empty? sent) is trying to find out whether we’re dealing with a sentence with content at all, whereas (number? (first sent))is trying to get some information about what sort of non-empty sentence we’re dealing in within the universe of non-empty sentences.

The book emphasizes that the values returned by if can be used as part of larger functions, consistent with Scheme’s overall approach. E.g. this works:

Boring Exercises

Exercise 6.1

βœ… Exercise 6.1.1

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 returns '(nowhere man), as I expected.

❌ Exercise 6.1.2

I misread how cond and this program work. I expected it to return 49 for some reason – I think that I thought the first line would have (empty?) evaluate 3 and return #f, and so then (square 7) would evaluate and return the true value 49. What actually happened was that the program returned 3.

The book actually has a relevant example. Let me reread that:

Don’t get into bad habits of thinking about the appearance of cond clauses in terms of “two parentheses in a row.” That’s often the case, but not always. For example, here is a procedure that translates Scheme true or false values (#t and #f) into more human-readable words true and false.

So what is happening? In this example, when the value is something that evaluates to #t, the 'true is returned. The value, despite not being a complex expression like ((equal? letter 'i) 1), has a truth value, and so when cond sees that that value is true, it then proceeds to return the “consequent”, which in this case is the word 'true.
In all other cases, truefalse returns the wordfalse.

I think the point is thatcond can, but need not have, a sub-expression as the first value which gets checked for its truth value. It can be a simple expression like value above. Or a procedure like empty?! Since basically everything in Scheme is true, empty? has a truth value too..

So in the cond for this exercise, empty? gets evaluated as true, and so the consequent 3 gets returned as a result.

βœ… Exercise 6.1.3

This returns goes.

βœ… Exercise 6.2

What values are printed when you type these expressions to Scheme? (Figure it out in your head before you try it on the computer.)

βœ… Exercise 6.2.1

This returns #t.

βœ… Exercise 6.2.2

This returns #f.

βœ… Exercise 6.2.3

βœ… Exercise 6.2.4

This returns #t.

βœ… Exercise 6.2.5

This returns #t.

βœ… Exercise 6.2.6

this returns #t.

βœ… Exercise 6.3

Rewrite the following procedure using a cond instead of the ifs:

Answer:

βœ… Exercise 6.4

**Β Rewrite the following procedure using an if instead of the cond:

Answer:

Real Exercises

βœ… Exercise 6.5

Write a procedure european-time to convert a time from American AM/PM notation into European 24-hour notation. Also write american-time, which does the opposite:

Answer:

NOTE: for ((equal? (first (bf us-time)) 'am) (first us-time)), replacing (first (bf with last, like AnneB does in her implementation, would be better…

Past Solution

Old answer, from a previous time I did the book:

For european-time, I think checking for whether the entire input is equal? to the us-time for the special cases of 12am and 12pm makes way more sense and is much more elegant and readable than the stuff i did last time with member? etc.

βœ… Exercise 6.6

Write a predicate teen? that returns true if its argument is between 13 and 19.

Answer:

AnneBΒ points out that the if statement is not necessary and this can be represented as:

Past Solution

Last time I went through Simply Scheme I did the following for this problem:

This works but would scale up really badly if you wanted to do a similar sort of thing but with a larger range of numbers.

βœ… Exercise 6.7 – Troubleshooting Scheme 🧐

Write a procedure type-of that takes anything as its argument and returns one of the words word, sentence, number, or boolean:

For this program I had to change the Scheme file I was using. I had to do this cuz the sentence? procedure was returning erroneous results.

I had been using this file https://gist.github.com/alexgian/5b351f367169b40a4ad809f0bb718e1f

And I had been using this declaration at the beginning of my Scheme files:

(I kept the simply_redef.scm file in a definitions subfolder in each place where I was storing .scm files).

For this exercise, I switched to using this declaration:

This caused sentence? to perform as expected πŸ™‚

So with that out of the way, my actual answer to the exercise:

test inputs:

outputs:

βœ… Exercise 6.8

Write a procedure indef-article that works like this:

Don’t worry about silent initial consonants like the h in hour.

Answer:

βœ… Exercise 6.9

Sometimes you must choose the singular or the plural of a word: 1 book but 2 books. Write a procedure thismany that takes two arguments, a number and a singular noun, and combines them appropriately:

In the court of doing this assignment, I greatly improved plural.

Answer. plural is where the interesting action is happening here. Note: some of the options in the upper-right of the code window may help with readability.

βœ… Exercise 6.10

Write a procedure sort2 that takes as its argument a sentence containing two numbers. It should return a sentence containing the same two numbers, but in ascending order:

answer:

Again I weirdly don’t make use of last.

❌ Exercise 6.11

NOTE: caught an error in this program after posting and changed the βœ… to an ❌. I discuss the error here

Write a predicate valid-date? that takes three numbers as arguments, representing a month, a day of the month, and a year. Your procedure should return #t if the numbers represent a valid date (e.g., it isn’t the 31st of September). February has 29 days if the year is divisible by 4, except that if the year is divisible by 100 it must also be divisible by 400.

I defined a program that looked for violations of the date rules and returned false if it found a violation, but returned true otherwise. I’ve included versions with both no comments and comments in case the commented version has readability issues. Note: some of the options in the upper-right of the code window may help with readability.

no comments:

with comments:

AnneB addressed some issues related to year-validity that I didn’t.

Past Solution 1

Here’s an earlier attempt of mine at solving this problem.

The organization seems solid. I like how concise my current solution is though.

βœ… Exercise 6.12

Make plural handle correctly words that end in y but have a vowel before the y, such as boy. Then teach it about words that end in x (box). What other special cases can you find?

I did this in an earlier problem.

I’ll do it clean here without the comments

AnneB‘s does more cases than mine does!

βœ… Exercise 6.13

Write a better greet procedure that understands as many different kinds of names as you can think of:

Answer. My remove-post-nominal-letters procedure handles a bunch of cases like the

Note: my previous work on this problem in past attempts didn’t deal with the MLK jr case at all.

I really like how buntine organized his solution hereΒ with the helper procedures.

βœ… Exercise 6.14

Write a procedure describe-time that takes a number of seconds as its argument and returns a more useful description of that amount of time:

answer:

Reflections

I should use the composability if if more to make stuff more concise.

I should consider using helper procedures more than I do.

I should think about whether procedures I’ve already built earlier in the chapter or elsewhere might be helpful with making later procedures (as AnneB did with exercise 6.14).

Simply Scheme Chapter 5 – Words and Sentences

Quotes from here or elsewhere in Simply Scheme unless otherwise specified. Refers to “the book” or “SS’ are to Simply Scheme.

Github here.

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 +)

My copy of Scheme returns a quoted + with a ' in front
My copy of Scheme returns a quoted + with a ' in front

' 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.

We can also use item to directly select any arbitrary letter in a word or word in a sentence.

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:

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:

By the way, why did we have to quote makes in the last example, but not 2? It’s because numbers are self-evaluating, as we said in Chapter 3. We have to quote makes because otherwise Scheme would look for something named makes instead of using the word itself. But numbers can’t be the names of things; they represent themselves. (In fact, you could quote the 2 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:

The result of substitution was not, as you might think,

but rather

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 and sent as formal parameters instead of word and sentence, 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, its count 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

This prints:

βœ… 5.1.2

I predict that this will print…

…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

I predict this will print either ‘2345 or maybe “‘2345”

It actually just printed

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:

then I get back 'potatotomato. But numbers lack the ' in front. Interesting.

βœ… 5.1.4

So I’d expect either (23 45) or '(23 45).

It was '(23 45).

❌ 5.1.5

I guess that this will print "".

It actually printed:

βœ… 5.1.6

I guess that this will print '()

I was correct.

❌ 5.1.7

❌ 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:

So first actually does “reach into” the sentence to pluck out a word. So does last by the way:

butfirst and butlast work differently:

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

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

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

Answer:

βœ… 5.2.2

Answer:

βœ… 5.2.3

Answer:

βœ… 5.2.4

I solved this one two ways:

βœ… Exercise 5.3

Explain the difference in meaning between (first 'mezzanine) and (first '(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)).

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

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

These have the same meaning – bf is just an abbreviation for butfirst.

βœ… Exercise 5.7

Explain the difference between (bf 'x) and (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?

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

This returns a sentence made up of two words, (matt wright).

βœ… 5.9.2

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:

βœ… Exercise 5.12

Which of the functions first, last, butfirst, and butlast 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:

βœ… 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.

Answer:

βœ… 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.

Answer:

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.

Answer:

βœ… 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.

βœ… Exercise 5.18

Try the following and explain the result:

(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:

βœ… 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:

Answer:

βœ… Exercise 5.20

Define a procedure to find somebody’s middle names:

Answer:

βœ… 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:

Two solutions:

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.