.rkt
file.
Topics: code reading, recursion
One way to really understand what is happening in a recursive procedure is
to trace the steps as Scheme evaluates the portions of the procedure in its
traditional “inside-out” form. For example, given the non-helper version of
sum
, we might write the following trace.
(sum (list 38 12 83))
; Not null
=> (+ (car (list 38 12 83) (sum (cdr (list 38 12 83)))
; Simplify car/cdr
=> (+ 38 (sum (list 12 83)))
; Not null
=> (+ 38 (+ (car (list 12 83)) (sum (cdr (list 12 83)))))
; Simplify car/cdr
=> (+ 38 (+ 12 (sum (list 83))))
; Not null
=> (+ 38 (+ 12 (+ (car (list 83)) (sum (cdr (list 83)))))))
; Simplify car/cdr
=> (+ 38 (+ 12 (+ 83 (sum null))))
; Null case
=> (+ 38 (+ 12 (+ 83 0)))
; Evaluate innermost expression
=> (+ 38 (+ 12 83))
; Evaluate innermost expression
=> (+ 38 95)
; Evaluate innermost expression
=> 133
Consider the two following versions of tally-odd
.
;;; Procedure:
;;; tally-odd
;;; Parameters:
;;; nums, a list of integers
;;; Purpose:
;;; Count how many values in nums are odd
;;; Produces:
;;; number-odd, a count of how many values are odd.
(define tally-odd-a
(lambda (nums)
(cond
[(null? nums)
0]
[(not (integer? (car nums)))
(error "tally-odd expects a list of integers. Your list contains "
(car nums))]
[(odd? (car nums))
(+ 1 (tally-odd-a (cdr nums)))]
[else
(tally-odd-a (cdr nums))])))
(define tally-odd-b
(lambda (nums)
(tally-odd-b-kernel nums 0)))
(define tally-odd-b-kernel
(lambda (remaining tally-so-far)
(cond
[(null? remaining)
tally-so-far]
[(not (integer? (car remaining)))
(error "tally-odd expects a list of integers. Your list contains "
(car remaining))]
[(odd? (car remaining))
(tally-odd-b-kernel (cdr remaining) (+ 1 tally-so-far))]
[else
(tally-odd-b-kernel (cdr remaining) tally-so-far)])))
Write traces of the evaluation of tally-odd-a
and tally-odd-b
(and
tally-odd-b-kernel
, since that’s where the real work happens) on the
input '(5 2 7 3 6)
.
(tally-odd-a '(5 2 7 3 6))
; Not empty, car is odd
=> (+ 1 (tally-odd-a (cdr '(5 2 7 3 6))))
...
(tally-odd-b '(5 2 7 3 6))
=> (kernel '(5 2 7 3 6) 0)
; Not empty, car is odd
=> (kernel (cdr '(5 2 7 3 6)) (+ 1 0))
...
Topics: recursion, conditionals
Document and write a recursive procedure, (contains? lst val)
,
that returns true (#t
) if val
appears in lst
and false
otherwise.
> (contains? (list 'a 'b 'c) 'a)
#t
> (contains? (list 'a 'b 'c) 'b)
#t
> (contains? (list 'a 'b 'c) 'c)
#t
> (contains? (list 'a 'b 'c) 'd)
#f
Topics: list recursion
As you know, the (index-of lst val)
procedure finds the
index of the first instance of val
in lst
. If val
is not in lst
,
it returns the value #f
.
Suppose index-of
did not exist. We could write it ourselves.
Document and write a recursive procedure, (my-index-of lst
val)
, that provides the first index of val
within
lst
. If the value does not appear, my-index-of
should return #f
.
> (my-index-of (list 'hop 'skip 'and 'jump) 'skip)
1
> (my-index-of (list 5 4 3 2 1 2 3 4 5) 5)
0
> (my-index-of (list "pencils" "paper" "index cards" "markers" "ball-point pens") "eraser")
#f
Note: You may not use list-ref
(or index-of
) in implementing my-index-of
.
Topics: list recursion
As you know, the (index-of lst val)
procedure finds the
index of the first instance of val
in lst
. If val
is not in lst
,
it returns the value #f
.
What if we wanted all of the indices, not just the first one? We’d probably have to write our own procedure.
Document and write a recursive procedure, (indices-of val
lst)
, that creates a list of all the position in lst
where val
appears. If the value does not appear, indices-of
should
return the empty list.
> (indices-of 'skip (list 'hop 'skip 'and 'jump))
'(1)
> (indices-of 'skip (list 'hop 'skip 'jump 'and 'skip 'again))
'(1 4)
> (indices-of 5 (list 5 4 3 2 1 2 3 4 5))
'(0 8)
> (indices-of "eraser" (list "pencils" "paper" "index cards" "markers" "ball-point pens"))
'()
Note: You may not use list-ref
(or index-of
) in implementing indices-of
.
Topics: list recursion
Document and write a procedure, (riffle2 first second)
, that
produces a new list containing alternating elements from the lists
first
and second
. If one list runs out before the other, then the
remaining elements should appear at the end of the new list.
> (riffle2 (list 'a 'b 'c) (list 'x 'y 'z))
'(a x b y c z)
> (riffle2 (list 'a 'b 'c) (iota 10))
'(a 0 b 1 c 2 3 4 5 6 7 8 9)
> (riffle2 (iota 10) (list 'a 'b 'c)
'(0 a 1 b 2 c 3 4 5 6 7 8 9)
> (riffle2 null (list 'a 'b 'c))
'(a b c)
Note: There’s a clever approach that involves looking only at the first list (but changing which list is first). You need not undertake this approach, but you should spend a minute or two thinking about it.
Topics: list recursion
Document and write a procedure, (riffle3 first second third)
,
that produces a new list containing alternating elements from the lists
first
, second
, and third. If one list runs out before the others,
continue riffling the remaining two lists.
> (riffle3 (list 'a 'b 'c) (list 'p 'q 'r) (list 'x 'y 'z))
'(a p x b q y c r z)
> (riffle3 (list 'a 'b 'c 'd) (list 'e 'f) (list 'g 'h 'i))
'(a e g b f h c i d)
> (riffle3 (list 'a 'b 'c) null (list 'd 'e 'f))
'(a d b e c f)
> (riffle3 (list 'c 'b 'a) (list 'd 'd 'd) (list 'e 'f 'g))
'(c d e b d f a d g)
Note: You are permitted to use riffle2
when you run out of
elements in one of the lists.
Topics: list recursion, sorting
Write but do not document a recursive procedure, (merge-sorted-lists
lst1 lst2)
, that takes as input two lists of strings
that are each ordered alphabetically and returns the combination
of those two lists, still in alphabetical order
You may not use sort
in your solution.
> (merge-sorted-lists '("alpha" "gamma" "yak" "zebra")
'("bracket" "cheese" "hello" "world" "zap"))
'("alpha" "bracket" "cheese" "gamma" "hello" "world" "zap" "zebra")
> (merge-sorted-lists '("alpha" "delta" "echo" "foxtrot" "xerxes")
'("alpha" "delta" "gamma" "xerxes"))
'("alpha" "alpha" "delta" "delta" "echo" "foxtrot" "gamma" "xerxes" "xerxes")
Note: The input lists must be in alphabetical order. You need not handle inputs not in alphabetical order.
Topics: lists, recursion, sorting
Write a procedure, (alphabetical-order? words)
, that takes a list
of strings as input and returns true if the words are in alphabetical
order (aka ASCII order) and false otherwise. You may assume that
all of the elements in the list are strings.
> (alphabetical-order? '("alpha" "beta" "delta" "epsilon"))
#t
> (alphabetical-order? '("alpha" "beta" "gamma" "delta" "epsilon"))
#f
> (alphabetical-order? '())
#t
We will primarily evaluate your work on correctness (does your code compute what it’s supposed to and are your procedure descriptions accurate); clarity (is it easy to tell what your code does and how it achieves its results; is your writing clear and free of jargon); and concision (have you kept your work short and clean, rather than long and rambly).