Logo
  • Home
  • Classes
  • Conveying Computing
  • Exams
  • Fractal Gallery
  • Guides
  • Problem Sets
  • Syllabus

PS8 Part 1 Comments

Problem 1. Modify the main method to print out a welcome message.
	public static void main(String[] args) {
		System.out.println("Java is an island in Indonesia.");
	}
Problem 2. Define a static factorial method that takes one int (an integer number) as its input, and outputs an int that is the factorial of the input. Modify the main method to use the factorial method you defined to print out the values the factorial for inputs 1 to 20. (See the hint below if your results appear to be correct until 12, but wrong after. It is not necessary to produce correct results above factorial(12).)
There are two main approaches: recursive and iterative.

Here is a recursive definition of factorial:

	public static int factorial(int n) {
		if (n == 1) {
			return 1;
		} else {
			return n * factorial(n - 1);
		}
	}
Here is an iterative definition using a for loop:
	public static int factorial(int n) {
		int res = 1;
		for (int i = 1; i <= n; i++) {
			res = res * i;
		}
		return res;
	}
Both run in linear time, but the recursive definition will be a bit slower and use a bit more memory in Java.
Problem 3. Define a static listReverse method that takes as input an ArrayList<Object> and reverses the order of the elements in that list (analogous to the mlist-reverse! procedure we defined in Scheme and Python). Your method should not return anything (return type is void), but should modify the input list.
The best solutions do not use any additional storage by reversing the list in-place, rather than making new copies.
	public static void listReverse(ArrayList<Object> p) {
		for (int i = 0; i < p.size() / 2; i++) {
			Object pi = p.get(i);
			p.set(i, p.get(p.size() - i - 1));
			p.set(p.size() - i - 1, pi);
		}
	}
This is similar to the Python procedure from class, but more complex in Java since we cannot swap the elements without introducing a new variable to store the result temporarily.

Problem 4. Answer this question by adding a comment to the bottom of Warmup.java with your answers.
  1. Is ArrayList<String> a subtype of ArrayList<Object>? You should be able to answer this question empirically by seeing what the Java compiler does in different situations.
  2. No. The easiest way to see this is to try,
    	ArrayList<Object> a = new ArrayList<String>();
    
    This produes a compiler error:
    Type mismatch: cannot convert from ArrayList<String> to ArrayList<Object>
    
    Note that String is a subtype of Object, so it is okay to add a String to an ArrayList<Object>.
  3. Are you happy with the answer? (Hint: will the listReverse procedure you defined work on all lists, like the Python version?)
  4. Personally, I find Java's typing rules to be far from ideal. They are not strict enough to guarantee that there are no run-time type errors (which would be a reasonable goal for a "truthy" language), but too restrictive to allow many useful code expressions. The listReverse procedure we defined only works on an ArrayList<Object> input, but it would make sense for it to work on an ArrayList<String>.
  5. As a bonus, why do you think Java has the typing rule it does?
  6. The danger in allowing an ArrayList<String> to be used where an ArrayList<Object> is expected is when new elements are added (or set) in the collection. Then, we could add an object that is not a String to an ArrayList<String>.

Problem 5. Modify the aazda interpreter to add the assignment special form, set!. It should behave like set! in Scheme. (Hint: make sure you understand the lookupVariable(String) method in the Environment class.)
To support assignment, we add updateVariable to the Environment class:
	public void updateVariable(String name, SVal value) {
		if (frame.containsKey(name)) {
			frame.put(name, value);
		} else if (parent != null) {
			parent.updateVariable(name, value);
		} else {
			throw new EvalError("Undefined name " + name);
		}
	}
Then, we add an evaluation rule for assignment:
	public static void evalAssignment(SExpr expr, Environment env) {
		assert isAssignment(expr);
		ArrayList def = expr.getList();
		if (def.size() != 3) {
			throw new EvalError("Bad assignment: " + expr.toString());
		}
		if (!def.get(1).isAtom()) {
			throw new EvalError("Bad assignment: name must be a string: "
					+ expr.toString());
		}

		String name = def.get(1).getAtom();
		
		if (!env.hasVariable(name)) {
			throw new EvalError("Bad assignment: name must be defined: "
					+ expr.toString());
		}
		
		env.updateVariable(name, meval(def.get(2), env))
	}
Note that most of the code is for error checking. The essence of the method is just:
	public static void evalAssignment(SExpr expr, Environment env) {
		ArrayList def = expr.getList();
		env.updateVariable(def.get(1).getAtom(), meval(def.get(2), env))
	}
But, we need the code to check that the variable is defined and report an evaluation error when it is not, and to check the structure of the assignment expression is correct.
Problem 6. Modify the aazda interpreter to add the begin special form. It should behave like begin in Scheme.
To implement begin, we evaluate each subexpression in order, saving the result of the last one in res to return:
	public static SVal evalBegin(SExpr expr, Environment env) throws EvalError {
		assert (isBegin(expr));
		SVal res = null;
		for (SExpr s : expr.getList().subList(1, expr.getList().size())) {
			res = meval(s, env);
		}
		return res;
	}
Note that (begin) with no expressions correctly evaluates to null, which represents no value in the interpreter.
Print Friendly Print Get a PDF version of this webpage PDF

Leave a Reply Cancel reply

You must be logged in to post a comment.

cs1120 | RSS | Comments RSS | Book | Using These Materials | Login | Admin | Powered by Wordpress