000000.rkt
, but replace 000000
with your generated random number. Email this file as an attachment to the instructor when you are finished with your exam.
Please read the exam procedures page for policies, turn-in procedures, and grading details. If you have any questions about the exam, check the Q&A at the bottom of this page. We will generally spend some time in class every day on questions and answers while the exam is in progress.
While the exam is out, please check back periodically to see if we have reported any new errata.
Complete the exam using the
exam02.rkt starter source
code. Please rename this file to 000000.rkt
, but replace
000000
with your generated random number.
The prologue for this examination will be via email, which you should send to your instructor by 10:30 p.m. on Friday evening. Your message should be titled CSC 151.01: Exam Prologue (your name).
For each problem, please include a short note about something that will help you solve the problem. Mostly, we want to see some evidence that you’ve thought about the problem. You might note some similar procedures you’ve written or problems you’ve solved in the past (e.g., in a lab or on a homework assignment). You might note procedures that you expect to use. You might sketch an algorithm. You might pose a question to yourself. (We won’t necessarily read this in a timely fashion, so if you have questions for your instructor, you should ask by email or in person.)
If, when looking at a problem, you think you already know the answer, you can feel free to write something short like “solved” or “trivial”.
Which of those problems do you expect to be the most difficult for you to solve? Why?
Conclude by answering the question What is an approach that you expect will help you be successful on this exam? For example, you might suggest that you will work thirty minutes on the exam each day, or work on the exam at 7pm each day, when your brain is most able to process information.
The epilogue for this examination will also be via email, which you should send to your instructor by 10:30 p.m. on the evening after the exam is due. Your message should be titled CSC 151.01: Exam Epilogue (your name). Include answers to the following questions.
What was the most difficult part of the exam?
What made that part difficult?
What are two things you can do to be more successful on the next exam?
Topics: Hash tables, for-each
As you may recall, in the lab on hash tables,
we manually changed sidekick
to sidekick-protagonists
. However,
it should be possible to generate the latter hash table algorithmically.
Here’s a sketch
Create a new hash table, which we'll call inverse
For each key in the hash table
Get the corresponding value
(hash-set! inverse value key)
Document and implement a procedure, (hash-invert hash)
that
takes a hash table as input and returns a new hash table whose
keys are the values of the original hash table and whose values
are the keys of the original.
> (define csfaculty (make-hash))
> (hash-set! csfaculty "Curtsinger" "Charles")
> (hash-set! csfaculty "Dahlby Albright" "Sarah")
> (hash-set! csfaculty "Eikmeier" "Nicole")
> (hash-set! csfaculty "Hamid" "Fahmida")
> (hash-set! csfaculty "Johnson" "Barbara")
> (hash-set! csfaculty "Osera" "Peter-Michael")
> (hash-set! csfaculty "Rebelsky" "Samuel")
> (hash-set! csfaculty "Stone" "John")
> (hash-set! csfaculty "Vostinar" "Anya")
> (hash-set! csfaculty "Walker" "Henry")
> (hash-set! csfaculty "Weinman" "Jerod")
> csfaculty
'#hash(("Curtsinger" . "Charles")
("Dahlby Albright" . "Sarah")
("Eikmeier" . "Nicole")
("Hamid" . "Fahmida")
("Johnson" . "Barbara")
("Osera" . "Peter-Michael")
("Rebelsky" . "Samuel")
("Stone" . "John")
("Vostinar" . "Anya")
("Walker" . "Henry")
("Weinman" . "Jerod"))
> (hash-ref csfaculty "Samuel")
Error! . . hash-ref: no value found for key
Error! key: "Samuel"
> (define ytlucafsc (hash-invert csfaculty))
> (hash-ref ytlucafsc "Samuel")
"Rebelsky"
> (hash-ref ytlucafsc "Fahmida")
"Hamid"
Note that each time we call hash-invert
, it should return a new
hash table. For example,
> (define hash1 (hash-invert '#hash(("a" . "apple") ("b" . "banana"))))
> (define hash2 (hash-invert '#hash(("red" . "apple") ("yellow" . "banana"))))
> hash1
'#hash(("apple" . "a") ("banana" . "b"))
> hash2
'#hash(("apple" . "red") ("banana" . "yellow"))
Note: When documenting the procedure, make sure to consider special cases, such as what happens when two keys in the original hash table share the same value.
Topics: randomness, local bindings, text generation
As you may recall, in the reading on randomness and the corresponding lab, we developed programs that wrote simple sentences. Here’s a variant of that code.
;;; Procedure:
;;; random-elt
;;; Parameters:
;;; lst, a non-empty list
;;; Purpose:
;;; Unpredictably pick an element of lst.
;;; Produces:
;;; val, a value
;;; Preconditions:
;;; [No additional]
;;; Postconditions:
;;; * val is an element of lst.
;;; * If lst contains more than one element, it is difficult to predict
;;; which element val is.
(define random-elt
(lambda (lst)
(list-ref lst (random (length lst)))))
;;; Procedure:
;;; random-sentence
;;; Parameters:
;;; [None]
;;; Purpose:
;;; Generate a simple, unpredictable, sentence.
;;; Produces:
;;; sentence, a string.
;;; Preconditions:
;;; [No additional]
;;; Postconditions:
;;; sentence is a simple English sentence.
(define random-sentence
(lambda ()
(string-append
"The "
(random-thing) " "
(random-elt transitive-verbs) " "
(add-indefinite-article (random-thing)) ".")))
;;; Procedure:
;;; capitalize
;;; Parameters:
;;; str, a string
;;; Purpose:
;;; Capitalizes a string
;;; Produces:
;;; capitalized, a string
;;; Preconditions:
;;; [No additional]
;;; Postconditions:
;;; * (substring capitalized 1) = (substring str 1)
;;; * If (string-ref str 0) is a lowercase letter,
;;; (string-ref capitalized 0) is (char-upcase (string-ref str 0))
;;; * Otherwise, (string-ref capitalized 0) is (string-ref str 0)
(define capitalize
(lambda (str)
(regexp-replace "^[a-z]" str string-upcase)))
;;; Procedure:
;;; add-indefinite-article
;;; Parameters:
;;; str, a string
;;; Purpose:
;;; Add the appropriate article to the front of a string
;;; Produces:
;;; extended, a string
;;; Preconditions:
;;; [No additional]
;;; Postconditions:
;;; * If str begins with a lowercase vowel, extended is "an str"
;;; * If str begins with an uppercase vowel, extended is "An str"
;;; * If str begins with an uppercase consonant, extended is "A str"
;;; * Otherwise, extended is "a str"
(define add-indefinite-article
(lambda (str)
(cond
[(regexp-match? #px"^[aeiou]" str)
(string-append "an " str)]
[(regexp-match? #px"^[AEIOU]" str)
(string-append "An " str)]
[(regexp-match? #px"^[A-Z]" str)
(string-append "A " str)]
[else
(string-append "a " str)])))
;;; Procedure:
;;; random-thing
;;; Parameters:
;;; [None]
;;; Purpose:
;;; Generate a simple, unpredictable, noun phrase.
;;; Produces:
;;; thing, a string
;;; Preconditions:
;;; [No additional]
;;; Postconditions:
;;; thing is a noun phrase, something that can serve as the
;;; subject or object of a transitive verb. However, thing
;;; still requires an article.
(define random-thing
(lambda ()
(string-append
(random-elt adjectives) " "
(random-elt nouns))))
;;; Values:
;;; adjectives
;;; nouns
;;; transitive-verbs
;;; Type:
;;; list of strings
(define adjectives
(list "heavy" "blue" "green" "hot" "cold" "disgusting"
"antipodean" "existential"))
(define nouns
(list "aardvark" "baboon" "civet" "dingo" "emu" "zebra"))
(define transitive-verbs
(list "saw" "threw" "attacked" "considered" "studied" "visited"))
One might hope to use some of these techniques to write stories, or at least story-like things. Unfortunately, each random sentence appears to be independent of every other sentence.
Document and write a procedure, (random-story)
, that generates
six random sentences with the restriction that the subject of
each sentence after the first must be either the subject or the
object of the previous sentence, with the choice between the two
made randomly.
> (random-story)
"The existential civet threw an existential dingo. The existential civet visited a green baboon. The green baboon considered a hot dingo. The hot dingo saw a blue civet. The blue civet studied an antipodean baboon. The antipodean baboon considered a green civet."
Note: You will not be able to call random-sentence
in writing
random-story
. Rather, you’ll need to generate the sequence of
subjects and objects and then combine them into a story. We would
recommend that you consider using local bindings to do so.
Note: You should feel free to choose different lists of nouns so that your stories are a bit more varied and interesting.
Topics: documentation, code reading, numeric values
Sometimes students (and professors) come up with difficult-to-read solutions to simple problems, like this one below:
(define what ( lambda ( scale)
(let* ( [p symbol?] [q list?]
[ r 'other ] [s 'symbol ] [t
'hash] [ u number?][v hash?
] [w 'list] [x 'string] [y
'number ] [z string?] [
image ( lambda ( drawing
)(cond [( u drawing ) y
] [ (and ( not (u
drawing) )( p drawing
) ) s] [ (q drawing)
w] [(or (q drawing)
( v drawing)) t][(
z drawing ) x][
else r] ))])(map
image scale))))
a. Clean up this procedure. You should reformat the code; rename the procedure, parameters, and variables; and simplify any unnecessarily complicated code.
b. Write 6P-style documentation for the code.
c. Explain how the code achieves its purpose.
Topics: regular expressions
In your solution to the Twitter problem in assignment 6, you may have written a procedure something like the following. (You probably didn’t use quite as many backslashes as we did.)
;;; Procedure:
;;; extract-tweet-text-field
;;; Parameters:
;;; tweetstring, a tweet
;;; Purpose:
;;; Extract the text field from the given string.
;;; Produces:
;;; text, a string
;;; Preconditions:
;;; tweetstring has the standard string/JSON representation of tweets,
;;; e.g., "{\"source\:": \"...\", \"id_str\": \"...\", ...}"
;;; Postconditions:
;;; text is the portion of the string corresponding to the text section.
(define extract-tweet-text-field
(lambda (tweetstring)
(regexp-replace* "^.*\"text\": \"(([^\"\\\\]|\\\\\")*?)\".*$" tweetstring "\\1")))
Let’s see how well it works.
> tweet
"{\"source\": \"Twitter for Android\", \"id_str\": \"812815404175421445\", \"text\": \".@FoxNews - \\\"Objectified\\\" tonight at 10:00 P.M. Enjoy!\", \"created_at\": \"Sun Dec 25 00:21:08 +0000 2016\", \"retweet_count\": 1482, \"in_reply_to_user_id_str\": null, \"favorite_count\": 5871, \"is_retweet\": false}\n"
> (extract-tweet-text-field tweet)
".@FoxNews - \\\"Objectified\\\" tonight at 10:00 P.M. Enjoy!"
> (extract-tweet-text-field "{\"text\": \"this is an example\"}")
"this is an example"
Not bad.
But we should be writing more general procedures.
Write, but do not document a procedure, (extract-field field str)
,
that takes two parameters, a field name (e.g., "source"
or "text"
)
and a string like the tweet above, and extracts the given field
from the string. (You need only support fields that name strings.)
;;; Procedure:
;;; extract-field
;;; Parameters:
;;; field, a string
;;; str, a string
;;; Purpose:
;;; Extract a field from a JSON string of the form
;;; "{\"field1\": \"contents1\", \"field2\": \"contents2\", ...}"
;;; Produces:
;;; contents, a string
;;; Preconditions:
;;; str contains a field of the given form.
;;; Postconditions:
;;; contents contains the associated value.
(define extract-field
(lambda (field str)
...))
Here are some examples of the procedure in action.
> (extract-field "text" tweet)
".@FoxNews - \\\"Objectified\\\" tonight at 10:00 P.M. Enjoy!"
> (extract-field "id_str" tweet)
"812815404175421445"
> (extract-field "source" tweet)
"Twitter for Android"
Your procedure should work with anything of a similar form, not just tweets.
> (extract-field "thing" "{\"thing\": \"abcde\", \"more\": \"efghi\"}")
"abcde"
> (extract-field "more" "{\"thing\": \"abcde\", \"more\": \"efghi\"}")
"efghi"
Topics: sorting, conditionals, precondition testing
Document and write a procedure, (sort-by-length strings)
, that takes
as input a list of strings and sorts that list by length. If two strings
are the same length, they should be ordered alphabetically.
> (sort-by-length (string-split "once upon a time in a land far far away there lived a strange language"))
'("a" "a" "a" "in" "far" "far" "away" "land" "once" "time" "upon" "lived" "there" "strange" "language")
> (sort-by-length (string-split "he took his vorpal sword in hand"))
'("he" "in" "his" "hand" "took" "sword" "vorpal")
> (sort-by-length (string-split "long time the manxome foe he sought"))
'("he" "foe" "the" "long" "time" "sought" "manxome")
Your procedure should check its preconditions and report appropriate error messages if those preconditions are not met.
> (sort-by-length "this is a bad input")
Error! sort-by-length: Invalid input; expected a list of strings, received "this is bad input"
Note that you will likely find it useful to write a helper procedure,
(shorter? str1 str2)
, that returns true when str1
is shorter
than str2
or when the two strings are of equal length and str1
alphabetically precedes str2
.
Topics: XML, processing XML, structs
We’ve considered a variety of techniques for representing structured data, including XML, lists, and Racket structs. Consider simple ‘blog posts. In representing such posts, we might want to store the following information.
In Racket, we would probably define that struct as follows.
(struct post (title author content tags views))
In XML, we might represent a simple ‘blog post as follows.
<post>
<title>A sample post</title>
<author>Some Body</author>
<content>This is my first post! Aren't you impressed?</content>
<tags>
<tag>First</tag>
<tag>Boring</tag>
<tag>Example</tag>
</tags>
<views>5</views>
</post>
In the list-based representation, that XML would appear as follows.
'(post (title "A sample post") (author "Some Body") (content "This is my first post! Aren't you impressed?") (tags (tag "First") (tag "Boring") (tag "Example")) (views "5"))
a. Write, but do not document, a procedure, (post->xml post)
,
that takes as a parameter a post
struct and returns an XML list
of the appropriate form.
> (post->xml (post "A" "B" "C" (list "D" "E") 3))
'(post (title "A") (author "B") (content "C") (tags (tag "D") (tag "E")) (views "3"))
> (xml->string (post->xml (post "A" "B" "C" (list "D" "E") 3)))
"<post><title>A</title><author>B</author><content>C</content><tags><tag>D</tag><tag>E</tag></tags><views>3</views></post>"
b. Write, but do not document, a procedure, (xml->post xml)
, that takes
the XML for a ‘blog post and returns a post
struct.
> (define sample (xml->post '(post (title "Title") (author "Author") (content "Content") (tags (tag "Tag1") (tag "Tag2")) (views "11"))))
> sample
#<post>
> (post-title sample)
"Title"
> (post-author sample)
"Author"
> (post-content sample)
"Content"
> (post-tags sample)
'("Tag1" "Tag2")
> (post-views sample)
11
> (define sample2 (xml->post (string->xml "<post><author>An author</author><title>A post</title><content>Some content.</content><tags><tag>This</tag><tag>That</tag></tags><views>42</views></post>")))
> sample2
#<post>
> (post-title sample2)
"A post"
> (post-author sample2)
"An author"
> (post-tags sample2)
'("This" "That")
> (post-views sample2)
42
>
We will post answers to questions of general interest here while the exam is in progress. Please check here before emailing questions!
section
?#|
before the pasted material. Put
a |#
after the pasted material.#|
and |#
or semicolons. You might also add a note or two as to
what you were trying to do.lambda
that looks like (define (proc params) body)
. Can I use that?(random 1000000)
. If you end up with a number less than six digits, add zeros to the left side of the number until you have six digits.; STUB
on some of the procedures. What does that mean?shorter?
procedure is core to this problem.sxpath-match
that might take a little time to
work through (send questions when you’re not sure, or look
at the reading/lab).'(list)
as an output when I use '('sym)
as my input? I would assume that I’d get '(symbol)
. [2019-03-07, 4:00 p.m.](list 'sym)
as
the input.pair?
. [2019-03-07, 4:00 p.m.]sort
work? [2019-03-06, 4:00 p.m.]sort
takes a list and a “less than” procedure that compares
two values and reorders the list so that each element is less
than the subsequent element. You don’t need to know the details
of how it does that (yet). For now, you can think of it as using
the second parameter to compare neighboring elements and swapping
them when they are out of order.shorter?
as you suggested and things are not working. [2019-03-09, 9:30 p.m.]shorter?
do with equal length strings? Remember that we said that shorter?
should return true for equal length strings only when the first alphabetically precedes the second.
> (shorter? "once" "time")
#t
> (shorter? "once" "away")
#f
map
or reduce
? [2019-03-09, 9:30 p.m.]map
and reduce
aren’t really intended for sorting.true
or false
? [2019-03-07, 4:00 p.m.]Please check back periodically in case we find any new issues.
.rkt
file. [MX, 1 point]random-story
procedure appears
incorrect. [JSC, 1 point]hash-invert
and
sometimes called hash-inverse
. [KS, 1 point]</tags>
in problem 6. [LT, 1 point]Some of the problems on this exam are based on—and at times copied from—problems on previous exams for the course. Those exams were written by Charlie Curtsinger, Janet Davis, Fahmida Hamid, Rhys Price Jones, Titus Klinge, Samuel A. Rebelsky, John David Stone, Henry Walker, and Jerod Weinman. Many were written collaboratively, or were themselves based upon prior examinations, so precise credit is difficult, if not impossible.
Some problems on this exam were inspired by conversations with our students and by correct and incorrect student solutions on a variety of problems. We thank our students for that inspiration. Usually, a combination of questions or discussions inspired a problem, so it is difficult and inappropriate to credit individual students.