You are on page 1of 10

Carleton University

SYSC 3101 – Programming Languages – Winter 2017


Midterm Exam – March 1, 2017
Solutions

Name:​__________________________________________________________________

Student Number:​_________________________________________________________

INSTRUCTIONS:

1. This exam is closed book. Calculators are permitted.

2. Exam questions will not be explained, and no hints will be given. If you think something
is unclear or ambiguous, make a reasonable assumption (one that does not contradict the
question), write it at the start of your solution, and answer the question.

3. The last page of this question paper is blank. You can use that page for rough work.
Nothing written on that page will be marked.

4. The crib sheet at the end of this question paper summarizes some Racket procedures that
you may find useful. You are free to use procedures that aren't listed on the sheet;
however, procedures other than the ones listed there aren't required for any of the
solutions.

5. All pages of this question paper, including the crib sheet and the rough-work page, must
be turned in.

Question 1 _____________/ 3

Question 2 _____________/ 4

Question 3 _____________/ 5

Question 4 _____________/ 5

Question 5 _____________/ 10

Question 6 _____________/ 3

Total __________________/ 30

1
Question 1 [3 marks]

Every powerful programming language provides three mechanisms for combining simple ideas
to form more complex ideas:

● primitive expressions​, which represent the simplest building blocks that the language
provides,
● means of combination​, by which compound elements are built from simpler ones, and
● means of abstraction​, by which compound elements can be named and manipulated as
units.

Consider this Racket expression:

(define area (* pi 10 10))

Racket associates ​pi​ with a value that approximates the mathematical constant 𝜋.

(a) List one ​primitive expression​ in this ​define​ special form. (1 mark)

Solution:
● 10​ is a primitive expression (a number)
● *​ is a primitive expression (primitive procedure)

(b) List one ​means of combination​ in the ​define​ special form. (1 mark)

Solution​:
● (* pi 10 10)​ A list of expressions forms a compound expression. In this example, the
compound expression represents the application of procedure ​*​ to the arguments (the
values of ​pi​ and ​10​)
● *​ is not a means of combination in a language where expressions are written using prefix
notation.

(c) List one ​means of abstraction​ in the ​define​ special form. (1 mark)

Solution:
● area​ (the name associated with the expression ​(* pi 10 10)​). ​define area​ was
also acceptable.
● pi​ (the name associated with the number that represents the the mathematical constant 𝜋)

2
Question 2 [4 marks]

On the ruled lines, write the values that Racket displays after it evaluates each expression. If an
expression returns a procedure, write "Procedure". If Racket displays an error message, write
"Error". If nothing is displayed, write "Nothing".

> (cons (list 5 10) (list 15 20))

Solution:​ Racket displays: ​'((5 10) 15 20)​ No marks were deducted if the only error was
omitting the leading quote, because some Scheme REPLs omit it.

I also accepted ​(list (list 5 10) 15 20)​, even though this is not what Racket displays,
because it is equivalent to: ​'((5 10) 15 20)

Explanation:​ The expression ​(cons (list 5 10) (list 15 20))​ is equivalent to:

(cons (cons 5 (cons 10 '())) (cons 15 (cons 20 '())))

We are creating a new list. Recall that Racket lists are implemented as linked lists of pairs.

● The first part of the first pair points to the list ​'(5 10)​. The second part of the first pair
points to the second pair.

● The first part of the second pair points to ​15​, and the second part of the second pair
points to the third pair.

● The first part of the third pair points to ​20​, and the second part of the third pair is the
empty list.

Common Error:​ Racket doesn't display ​'(5 10 15 20)​. This is a list of 4 integers. Two
cons​ expressions that produces this list are:

(cons 5 (cons 10 (cons 15 (cons 20 '()))))

(cons 5 (cons 10 (list 15 20)))

To create this list from the two lists, ​(list 5 10)​ and ​(list 15 20)​, we use ​append​, not
cons​:

(append (list 5 10) (list 15 20))

Common Error:​ Racket doesn't display ​'((5 10) (15 20))​. This is a list of two lists. A
cons​ expression that produces this list is:

(cons (list 5 10) (cons (list 15 20) '()))

The same list can be produced by using ​list​ instead of ​cons​:

(list (list 5 10) (list 15 20))

3
> (cdr (car '((1 2) (3 4))))

Solution:​ Racket displays ​'(2)​ No marks were deducted if the only error was omitting the
leading quote.

Explanation:

(car '((1 2) (3 4)))​ yields the list ​'(1 2)​, and ​(cdr '(1 2))​ yields the list ​'(2)

Common Error:​ Many students correctly deduced that the ​cdr​/​car​ expression would select the
second element, ​2​, from the first list ​'(1 2)​, but stated that Racket would display ​2​. It doesn't:
cdr​ always returns a list.

> (define (adder-1 x)


(lambda (y) (+ x y)))
> ((adder-1 5) 10)

Solution:​ Racket displays ​15​. ​(adder-1 5​) returns a ​lambda​ procedure in which ​x​ is bound to
5​. When this procedure is called with argument ​10​, the body of the ​lambda​ evaluates to ​(+ 5
10)​, which is ​15​.

> (define (adder-2 x)


(lambda (x y) (+ x y)))
> ((adder-2 5) 10 20)

Solution:​ Racket displays ​30​. ​(adder-2 5​) returns a ​lambda​ procedure that has two formal
parameters, ​x​ and ​y​. When this procedure is called with arguments ​10​ and ​20​ the body of the
lambda​ evaluates to ​(+ 10 20)​, which is ​30​. (The ​5​ bound to ​adder-2​'s formal parameter ​x
isn't used in the ​lambda​.)

4
Question 3 [5 marks]

Consider this procedure:

(define (mystery n csum)


(if (= n 0)
csum
(mystery (- n 1) (+ csum n))))

Use the substitution model to illustrate the process generated by this procedure application:

(mystery 3 1) ; (3 marks)

Solution:
(mystery 3 1)
==> (mystery (- 3 1) (+ 1 3)) ; subst. args into formal params
; n and csum
==> (mystery 2 4) ; evaluate subexpressions & apply mystery
==> (mystery (- 2 1) (+ 4 2)) ; subst. args into formal params
; n and csum
==> (mystery 1 6) ; evaluate subexpressions & apply mystery
==> (mystery (- 1 1) (+ 6 1)) ; subst. args into formal params
; n and csum
==> (mystery 0 7) ; evaluate subexpressions & apply mystery
==> 7

Common Error:​ most students who applied the substitution model incorrectly used the wrong
value of ​n​ when evaluating ​(+ csum n)​. Often, these students skipped over steps; e.g.,
combining the argument substitution step with the next recursive call, and lost track of the values
of the arguments.

Is this process recursive or iterative? (1 mark) Briefly explain your answer. (1 mark)

Solution:​ the process is ​iterative​. (The procedure is recursive, but the process it generates is
iterative.)

Notice that ​mystery​ produces ​csum + n + n-1 + … + 2 + 1​. The accumulating sum is
the procedure's second argument.

I accepted any explanation that showed that you understand that an iterative procedure will
execute in constant space (e.g., no expansion followed by contraction in the chain of procedure
calls, the addition operation isn't deferred until ​mystery​ returns, etc.)

5
Question 4 [5 marks]

Assume you have been provided with procedure ​(power x n)​ that calculates xn, n ≥ 0.

Define a recursive procedure ​sum-powers​ that takes two arguments, a number ​x and an integer
n, n ≥ 1. The procedure calculates x + 2x2 + 3x3 + ... + n · xn by means of a recursive process.
Your ​sum-powers​ procedure must use the ​power​ procedure. Do not define ​power​.

Solution:

The formulae for the two cases this procedure must handle are:

f (x, n) = x, when ​n = 1 (base case)

f (x, n) = n · xn + (n − 1) xn−1 + ... + 3x3 + 2x2 + n = n · xn + f (x, n − 1), when ​n > 1 (recursive case)

Converting these formulae to Racket is straightforward:

(define (sum-powers x n)
(if (= n 1)
x
(+ (* n (power x n))
(sum-powers x (- n 1)))))

No marks were deducted for using this base case: ​(if (= n 0) 0 … )​, even though this
results in an extra recursive call to ​sum-powers​.

Some students defined a recursive inner helper procedure that was called by ​sum-powers​. No
marks were deducted if the resulting process was recursive; however, make sure you understand
why a helper procedure isn't needed. Sometimes, the helper implemented an iterative process,
which was incorrect, as the question specified that the procedure generate a recursive process.

It was not necessary for your procedure to type-check or range-check the values bound to the
parameters; e.g., check if ​x​ is a number and ​n​ is a positive integer.

6
Question 5 [10 marks]

(a) (5 marks) Define a recursive procedure ​count-multiples​ that takes two arguments, a list
of integers and an integer n, n ≥ 1. The procedure counts the number of elements in the list that
are a multiple of ​n, by means of a recursive process. For example,

> (count-multiples '(1 2 3 4 5 6) 1) ; returns 6


> (count-multiples '(1 2 3 4 5 6) 2) ; returns 3
> (count-multiples '(1 2 3 4 5 6) 3) ; returns 2
> (count-multiples '(1 2 3 4 5 6) 7) ; returns 0

Solution:​ This procedure has to handle 3 cases:

1. The number of multiples in an empty list is 0 (base case).

2. If the first element in a list is a multiple of ​n, the number of multiples equals 1 plus the
number of multiples in the rest of the list (recursive case).

3. If the first element in a list is not a multiple of ​n, the number of multiples equals the
number of multiples in the rest of the list (recursive case).

(define (count-multiples lst n)


(cond ((empty? lst) 0)
((= (remainder (car lst) n) 0)
(+ 1 (count-multiples (cdr lst) n)))
(else (count-multiples (cdr lst) n))))

This is clearly a recursive process, because the addition is deferred until ​count-multiple
returns.

As with Question 4, there was no requirement to type-check or range-check the arguments.

Some students defined a unnecessary recursive helper procedure that is called by


count-multiples​. Marks were deducted only if the generated process is iterative.

7
(b) (5 marks) Rewrite your solution to part (a) as procedure that generates an iterative process.

Solution:​ We need a recursive helper process that has three parameters: the list, ​n, and an
accumulating count of the number of elements that are multiples of ​n. The procedure executes in
constant space (​result​ contains the correct count of multiples when the base case is reached),
so the process is iterative.

(define (count-multiples lst n)


(define (helper lst n result)
(cond ((empty? lst) result)
((= (remainder (car lst) n) 0)
(helper (cdr lst) n (+ result 1)))
(else (helper (cdr lst) n result))))

(helper lst n 0))

Common errors:

1. The base case returns 0 instead of the accumulated result; e.g., ​((empty ? lst) 0)

2. The expression for the third argument passed to ​helper​ is incorrect; i.e., using ​result
when ​(+ result 1)​ is required, or vice-versa.

8
Question 6 [3 marks]

Racket provides a procedure ​(list-ref lst pos)​, which takes a list, ​lst​, and a
non-negative position, ​pos​. It returns the list element at position ​pos​. The list's first element is at
position 0. For example,

> (list-ref '(10 20 30 40 50) 0) ; returns 10


> (list-ref '(10 20 30 40 50) 4) ; returns 50

Define a procedure ​ordinal​ that takes a non-negative integer argument ​n​. It returns a procedure
that takes one argument, a list, and returns the ​n'th element in the list, counting from ​one​ (1). For
example:

> (define third (ordinal 3))


> (third '(10 20 30 40 50)) ; returns 30, the third element
> (define first (ordinal 1))
> (first '(a b c d e)) ; returns 'a, the first element

Hint: use ​list-ref​.

Solution:

(define (ordinal n)
(lambda (lst) (list-ref lst (- n 1))))

Notice that ​list-ref​'s second argument is ​(- n 1)​, not ​n​, because ​ordinal​ counts from 1,
but ​list-ref​ considers 0 to be the position of the first element in the list.

Common errors:

● ordinal​ calls the ​lambda​ (or calls ​list-ref​) instead of returning a procedure;

● ordinal​ has two formal parameters (e.g., a list and a position);

● the procedure returned by ​ordinal​ has two formal parameters (e.g., a list and a
position).

9
Crib Sheet

Numbers

+​, ​-​, ​*​, ​/​ are the addition, subtraction, multiplication and division operators.

=​, ​<​, ​<=​, ​>​, ​>=​ are the numeric comparison operators, and return ​#t​ or ​#f​.

(even? n)​ returns ​#t​ if ​n​ is an even integer, ​#f​ otherwise.

(odd? n)​ returns ​#t​ if ​n​ is an odd integer, ​#f​ otherwise.

(quotient n m)​ returns the integer result when integer ​n​ is divided by integer ​m​.

(remainder n m)​ returns the integer remainder when integer ​n​ is divided by integer ​m​. The
remainder has the same sign as ​n​.

Pairs and Lists

null​, ​empty​, ​'()​ all represent the empty list.

(pair? v)​ returns ​#t​ if ​v​ is a pair, ​#f​ otherwise.

(cons? v)​ is the same as ​(pair? v)​.

(null? v)​ returns ​#t​ if ​v​ is the empty list, ​#f​ otherwise.

(empty? v)​ is the same as ​(null? v)​.

(​list? v)​ returns ​#t​ if ​v​ is a list; that is, if ​v​ is the empty list or a pair whose second element
is a list.

(cons a b)​ returns a newly allocated pair whose first element is ​a​ and second element is ​b​.

(car p)​ returns the first element of the pair ​p​.

(cdr p)​ returns the second element of the pair ​p​.

(list v​1​ v​2​ … v​n)​


​ returns a newly allocated list containing all the ​v​'s as its elements.

(length lst)​ returns the number of elements in list ​lst​.

(append lst​1​ lst​2​ … lst​n)​ ​ returns a list containing all the elements of the given lists in
order. All lists except the last one are copied, but ​lst​n​ is appended, not copied.

(member v lst)​ locates the first element in ​lst​ that is ​equal?​ to ​v​. If that element exists,
the tail of ​lst​ starting with that element is returned. Otherwise, ​#f​ is returned.

10

You might also like