CS 60 Mid-term Solutions, Spring 1996 ----------------------------------------------------------------------------- Problem 1 Representing the piles in binary: 32 16 8 4 2 1 63 = 2^6-1 = 1 1 1 1 1 1 31 = 2^5-1 = 0 1 1 1 1 1 1 = 0 0 0 0 0 1 ---------------------------------- nim sum = 1 0 0 0 0 1 = 33 To make the nim sum 0, we need to nim-add (= subtract) 33 from some pile. The only pile which is large enough is the one with 63. The player therefore should take 33 from the pile with 63 leaving 30. (The nim sum will then be 30 + 31 + 1 = 0, so that checks.) ----------------------------------------------------------------------------- Problem 2 cons: The second argument must be a list. The first can be anything. The number of elements in the result is 1 + the number in the second argument. cons(A0, [A1, A2, ...., An]) == [A0, A1, A2, ...., An] rex: cons(A, L) = [A | L]; list: Both elements can be anything. The number of elements in the result is 2. list(A0, A1) == [A0, A1] rex: list(A, B) == [A, B]; appnd: Both elements must be lists. The number of elements in the result is the sum of the numbers in the two arguments. rex: appnd(A, B) == A == [] ? B : [first(A) | appnd(rest(A), B)]; All three functions create new lists. However, cons and appnd share, rather than copy, their second arguments. ----------------------------------------------------------------------------- Problem 3 a. The argument to map would be the function (X) => [X, X]. b. double_leaves(A) => atomic(A) ? [A, A]; // basis, tree = 1 leaf double_leaves(L) => map(double_leaves, L); // induction step ----------------------------------------------------------------------------- Problem 4 inverse(f)(x) = inv(f, x, 0); inv(f, x, n) = f(n) == x ? n : inv(f, x, n+1); Note that f must be carried as a function argument, so that can be applied to successive values of n. It is not correct to pass it as f(n). ----------------------------------------------------------------------------- Problem 5 a = p -> next; b = p -> previous; a -> next -> previous = p; // 1 p -> next = a -> next; // 2 b -> next = a; // 3 a -> next = p; // 4 a -> previous = b; // 5 p -> previous = a; // 6 ------> represents before transpose ......> represents after transpose (2) ,,,,,,,,,,,,,,,,,,,,,,,, (3) . , ........................ . . . . . b . p . . a . | . | . . | . V . V . V V V |----.-| |----.-| (4) |------| |------| | . | | . |<....... | | | | | | | | | | | | --------->| -------->| -------->| | |------| |------| |------| |------| | | | | | | | | |------| |------| |------| |------| | |<--------- |<-------- |<-------- | | | | | | | | | | | | .......>| . | | . | |------| |------| (6) |-.----| |-.----| ^ ^ . . . (5) . . . (1) ......................... . . . ........................ ----------------------------------------------------------------------------- Problem 6 In the language: *******11111111 Not in the language: *******1111111* Derivation tree for *******11111111: S /|\ * S S /|\ \ * S S 1 /|\ \ * S S 1 /|\ \ * S S 1 /|\ \ * S S 1 /|\ \ * S S 1 /|\ \ * S S 1 | | 1 1 // Executable C++ code #include typedef int outcome; // outcome of parse typedef int bit; // bit value of expression const outcome success = 1, failure = 0; outcome S(bit &value) // S -> '0' | '1' | '+' S S | '*' S S { char c; if( !cin.get(c) ) return failure; switch( c ) { case '0': value = 0; return success; // S -> '0' case '1': value = 1; return success; // S -> '1' case '+': // S -> '+' S S | '*' S S case '*': { bit x, y; if( !S(x) ) return failure; // evaluate 2 arguments if( !S(y) ) return failure; switch( c ) { case '+': value = (x + y)%2; break; // S -> '+' S S case '*': value = (x * y)%2; break; // S -> '*' S S } return success; } default: return failure; } } main() { bit value; if( S(value) ) cout << "value is: " << value << endl; else cout << "syntax error" << endl; }