Cs1101s Exam 2017 Solution
Cs1101s Exam 2017 Solution
Cs1101s Exam 2017 Solution
---SOLUTION----
CS1101S — PROGRAMMING METHODOLOGY
(Semester 1 AY2017/2018)
INSTRUCTIONS TO STUDENTS
1. This assessment paper contains FIVE (5) questions and comprises TWENTY-FIVE (25)
printed pages, including this page and two sheets of scratch paper at the end.
2. The full score of this paper is 80 marks.
3. This is a CLOSED BOOK assessment, but you are allowed to use ONE A4 sheet of
notes.
4. Answer ALL questions within the space provided in this booklet.
5. Where programs are required, write them in the Source Week 11 language.
6. Write legibly with a pen or pencil. UNTIDINESS will be penalized.
7. Do not tear off any pages from this booklet.
8. Write your Student Number below USING A PEN. Do not write your name.
Student No.:
Draw the box-and-pointer diagrams of results of evaluating the following Source statements.
A.1. [1 mark]
pair(4, []);
A.2. [1 mark]
list(5);
Page 2 of 25
CS1101S
A.3. [2 marks]
A.4. [2 marks]
pair([], pair([], pair([], [])));
Page 3 of 25
CS1101S
Recall the function equal from the lectures. When applied to two trees of numbers, equal
returns true, if and only if they have exactly the same structure (same pairs and empty lists)
and the same numbers at their leaves.
In this question, we would like to be a bit more liberal, and define two trees to be similar, if
they have the same structure and if the corresponding number leaves differ by at most 1.
Examples:
similar(list(4, list(5,6)),
list(4, [], list(5,6))); // false (not same structure)
similar(list(4, list(5,6)),
list(5, list(3,7))); // false (too big difference)
Define the function similar such that similar(tn1, tn2) returns true if tn1 and
tn2 are similar and false otherwise. You can assume that both tn1 and tn2 are trees of
numbers. Make your function as simple and clear as possible. You can assume that the
function is_number is available, with the obvious meaning.
Page 4 of 25
CS1101S
For two similar trees, the question arises at how many places they differ. Write a function
differences such that differences(tn1, tn2) returns the number of places where
tn1 and tn2 have different numbers. You can assume that tn1 and tn2 are similar trees of
numbers.
Examples:
differences(list(4, [], list(4,6), 8),
list(5, [], list(4,7), 8)); // returns 2
differences(list(4,5,6,7),
list(4,5,6,7)); // returns 0
Make your function as simple and clear as possible. You can assume that the function
is_number is available, with the obvious meaning.
Page 5 of 25
CS1101S
function increment(nt) {
return map_tree(function (x) { return x + 1; }, nt);
}
Page 6 of 25
CS1101S
We shall use literal Source objects in order to implement key-value stores. For example, the
following Source object can be seen as a key-value store.
var my_key_value_store =
{"NUS": {"students": {"Chris" : {"mobile": "98765432",
"home" : "65432109" },
"Sam" : {"mobile": "44556677" } },
"staff" : {"Peter" : {"office": "65166632" } } },
"CERN": {"Tim" : {"office": "59843726" } } };
Draw the environment diagram of the environment after evaluating the program above.
Page 7 of 25
CS1101S
The string "__proto__" enjoys special treatment in Source (and JavaScript) objects.
Consider the following Source object.
var your_key_value_store =
{ "a" : { "b" : { "c" : "1", "e": "2" },
"__proto__" : { "f" : "3", "g": "4" } },
"__proto__" : { "h" : { "i" : "5", "j": "6" } } };
What is the result of the following operations:
B.1. [1 mark]
your_key_value_store.a.b.c;
“1”
B.2. [1 mark]
your_key_value_store.a.f;
“3”
B.3. [1 mark]
your_key_value_store.h.b;
undefined
B.4. [1 mark]
your_key_value_store.h.j;
“6”
We shall assume henceforth that "__proto__" does not occur in keys of key-value
stores.
Page 8 of 25
CS1101S
A key-value store is initially empty, and thus is represented by the empty object.
function make_empty_key_value_store() { return {}; }
In order to add entries to the key-value store, we require a function put that takes a store as
first argument, followed by a key, which is a list of strings, followed by the new value that we
want to enter. The string elements of the key are used to successively access the properties of
the respective object, starting with the first element (also called the major key) and the whole
store. The process will create objects whenever necessary, on the path to where the value
belongs.
After the following session, my_key_value_store_2 will refer to an object with the
same structure and values as the object my_key_value_store in Part A.
var my_key_value_store_2 = make_empty_key_value_store();
put(my_key_value_store_2,
list("NUS", "students", "Chris", "mobile"), "98765432");
put(my_key_value_store_2,
list("NUS", "students", "Chris", "home" ), "65432109");
put(my_key_value_store_2,
list("NUS", "students", "Sam", "mobile"), "44556677");
put(my_key_value_store_2,
list("NUS", "staff", "Peter", "office"), "65166632");
put(my_key_value_store_2,
list("CERN", "Tim", "office"), "59843726");
Define the function put. The call put(store, key, new_value) should always
succeed in writing the string new_value to any store, such that it can later be retrieved
with the list of strings given in key. If the store already has a value (which might even be
an object and not a string) under the given key, that value is replaced by new_value.
Page 9 of 25
CS1101S
In order to access a key-value-store, we need a function get that is applied to a store and a
key. The function get(store, key) should always succeed for a given store my_store
and a given list of strings key. If store contains the value val under key, the function
get should return val. If there is no string value under key, the function get should
return the value undefined. You can assume there are functions is_string and
is_object to check if a given value is a string or an object, respectively.
Examples:
get(my_key_value_store_2,
list("NUS", "students", "Chris", "mobile")); // "98765432"
get(my_key_value_store_2,
list("NUS", "students")); // undefined
get(my_key_value_store_2,
list("SFU", "students", "Chris", "mobile")); // undefined
Page 10 of 25
CS1101S
The diagram below illustrates how the sorted array can be obtained from the histogram.
Page 11 of 25
CS1101S
It will be convenient to start with a histogram whose elements are all 0. Write a function
array_with_zeros such that a call array_with_zeros(n) returns an array of
length n whose values at indices 0 to n - 1 are all 0.
For example,
array_with_zeros(5);
should return the array [0, 0, 0, 0, 0].
function array_with_zeros(n) {
var a = [];
for (var i = 0; i < n; i = i + 1) {
a[i] = 0;
}
return a;
}
Page 12 of 25
CS1101S
Page 13 of 25
CS1101S
To fill the result array, we may need a function enter_copies such that
enter_copies(arr, n, v, start) enters into arr exactly n copies of a given
value v, starting at index start. For example, consider the array
var some_array = [1, 1, 1, 1, 1, 1, 1, 1, 1];
The call
enter_copies(some_array, 4, 8, 2);
should enter 4 copies of the value 8 into some_array, starting at position 2. Thus, after the
call, some_array should have the form [1, 1, 8, 8, 8, 8, 1, 1, 1].
Page 14 of 25
CS1101S
We now generate a sorted array from a given histogram. For each index i of the histogram,
we enter the given number of copies of i into the sorted array, starting from 0. For example,
generate_sorted([0, 2, 1, 1, 0, 2, 0, 1, 0, 0, 1, 0, 0]);
should return the array [1, 1, 2, 3, 5, 5, 7, 10].
function generate_sorted(histogram) {
var sorted_array = [];
var len = array_length(histogram);
var sorted_pointer = 0;
for (var i = 0; i < len; i = i + 1) {
enter_copies(sorted_array,
histogram[i], i, sorted_pointer);
sorted_pointer = sorted_pointer + histogram[i];
}
return sorted_array;
}
The number of array operations for solving a sorting problem of size n using
counting sort has order of growth:
Ө(n)
Page 15 of 25
CS1101S
A. [4 marks]
function Body(x, y, z) {
this.x = x;
this.y = y;
this.z = z;
}
Page 16 of 25
CS1101S
B. [6 marks]
Page 17 of 25
CS1101S
C. [4 marks]
For our orrery to work, we need to keep track of the speed of the bodies, and not just their
position. For this we assume we can use ‘speed’ objects. Define a function MovingBody
that allows you to create new bodies using
var moving_earth = new MovingBody(145.9, 76.4, 0.0,
initial_speed_of_earth);
// initial_speed_of_earth is given object stating speed of earth
Your function MovingBody should inherit from the function Body and make use of Body
in its definition.
Also define a method get_speed such that we can retrieve the current speed of
moving_earth by
var current_earth_speed = moving_earth.get_speed();
MovingBody.Inherits(Body);
MovingBody.prototype.get_speed
= function() { return this.speed; };
Page 18 of 25
CS1101S
JavaScript’s strict mode alerts the programmer of various obvious programming errors using
exceptions. In this question, you are required to simulate one aspect of the behaviour of strict
mode in the meta-circular interpreter for Source (MetaSource) by displaying error messages.
Strict mode insists that function parameters are unique. For example, a function
function power(x, x) {
return x === 0 ? 1 : x * power(x, x – 1);
}
lists x twice as parameter of power. Like JavaScript, MetaSource accepts this program
although this is clearly a programming error and the meaning of the program is not clear.
Modify the implementation of function definition in MetaSource such that any function
definition where the function parameters are not unique displays an error and returns
undefined. For example, the evaluation of the function definition above will lead to the
display of the string
“parameters in function definition not unique”
and the value undefined.
function evaluate_function_definition(stmt,env) {
return make_function_value(
pair("this",
function_definition_parameters(stmt)),
locals(function_value_body(stmt)),
function_definition_body(stmt),
env);
}
Page 19 of 25
CS1101S
function distinct(xs) {
if (is_empty_list(xs) || is_empty_list(tail(xs))) {
return true;
} else {
if (is_empty_list(member(head(xs)))) {
return distinct(tail(xs));
} else {
return false;
}
}
}
function evaluate_function_definition(stmt,env) {
var params = function_definition_parameters(stmt);
if (distinct(params)) {
return make_function_value(
pair("this",
function_definition_parameters(stmt)),
locals(function_value_body(stmt)),
function_definition_body(stmt),
env);
} else {
display("parameters in function \
definition not unique”);
}
}
Page 20 of 25
CS1101S
JavaScript allows property assignment to primitive values such as boolean values, numbers
and strings. Any such attempts are just ignored by the JavaScript evaluator. For example,
true["aaa"] = 1; // has no effect
"bbb" . ccc = 2; // has no effect
123["ddd"] = 3; // has no effect
All these property assignments succeed in JavaScript, but have no effect. Most of the time,
such operations will be a programming error, and the author intended something else.
JavaScript’s strict mode therefore generates an exception in these situations.
Modify property assignment such that error messages are displayed, in the examples above:
"expecting array/object/function value before [, found value true"
"expecting array/object/function value before [, found value 'bbb'"
"expecting array/object/function value before [, found value 123"
Hint: Recall the current implementation of evaluation property assignment for MetaSource
as follows.
function evaluate_property_assignment(stmt,env) {
var obj = evaluate(object(stmt), env);
var prop = evaluate(property(stmt), env);
var val = evaluate(value(stmt), env);
obj[prop] = val;
return val;
}
You can assume that the builtin functions is_object, is_array and is_function are
available and return true if and only if their argument is a Source object, Source array or
Source function, respectively.
function evaluate_property_assignment(stmt,env) {
var obj = evaluate(object(stmt), env);
var prop = evaluate(property(stmt), env);
var val = evaluate(value(stmt), env);
if (is_object(obj) || is_array(obj) || is_function(obj)) {
obj[prop] = val;
return val;
} else {
display("expecting array/object/function \
value before [, found value " +
obj);
return undefined;
}
}
Page 21 of 25
CS1101S
JavaScript supports a function eval that takes a string as argument, parses it, evaluates the
parsed program, and returns the result. This question explores what environment can or
should be used for the evaluation.
Recall that primitive functions such as pair, head and tail are defined for MetaSource as
follows:
// the global environment has bindings for all
// builtin functions, including the operators
var primitive_functions = list( pair("pair", pair),
pair("head", head),
pair("tail", tail),
…
);
// setup_environment makes an environment that has
// one single frame, and adds a binding of all variables
// listed as primitive_functions ...
// The values of primitive functions are objects tagged
// with "primitive" whose “implementation” is the tail
// of the pair
function setup_environment() {
var initial_env = enclose_by(an_empty_frame,
the_empty_environment);
for_each(function(x) {
define_variable(head(x),
{ tag : "primitive",
implementation: tail(x) },
initial_env);
},
primitive_functions);
…
return initial_env;
}
// parse_and_evaluate
function parse_and_evaluate(str) {
return evaluate_toplevel(parse(str),
the_global_environment);
}
Our approach to provide JavaScript’s eval function in MetaSource shall be to add a line for
eval as follows:
var primitive_functions
= list(pair("pair", pair),
pair("head", head),
pair("tail", tail),
pair("eval", parse_and_evaluate),
…
);
Page 22 of 25
CS1101S
Using this modification of the evaluator, what are the results of the following Source
programs?
C.1. [2 marks]
var x = 1;
parse_and_evaluate("eval('var x = 2; x + x;');");
C.2. [2 marks]
var x = 1;
parse_and_evaluate("var x = 2; eval('x + x;');");
C.3. [2 marks]
var x = 1;
parse_and_evaluate("var x = 2; \
function f(x) { \
return eval('x + x;'); \
} \
f(3);");
Page 23 of 25
CS1101S
Page 24 of 25
CS1101S
Page 25 of 25