Problem Set 11
This is the final problem set. You have until midnight, Tuesday December 8 to submit it.
Purpose This problem set (primarily) concerns the design of accumulator-style functions.
Problem 1: A number, n>1, is prime if it is not divisible by any numbers besides 1 and itself, such as 2, 3, 5 and 7.
Design the function prime? which consumes a Natural Number, n and returns true if it is prime and false otherwise. Use the fact that if n is not prime, one if its factors must be less than or equal to the square root of n.
Design the function list-primes which consumes a Natural Number, n, and produces the list of prime numbers up to n.
Design the function fibonacci, (without accumulators) which consumes a Natural Number and produces its Fibonacci number. For example, (fibonacci 11) should produce 89.
Use accumulators to design a more efficient version of fibonacci.
Design a function, list-fibonacci, that consumes a Natural Number and produces the list of Fibonacci numbers from F0 to Fn.
Problem 3: Interpreter
Add the and and or boolean operators. Note that these are not primitive functions. Rather, they are new control operators (like cond): since they do short-circuit evaluation, they do not necessarily evaluate all of their parts.
Here are the semantics for these two forms, in English:(and exp1 exp2 ...) evaluates the exp expressions from left to right. As soon as some expression produces false, evaluation of the and form stops and the whole expression produces false. If all the exp expressions produce true, then the entire and produces true.
(or exp1 exp2 ...) evaluates the exp expressions from left to right. As soon as some expression produces true, evaluation of the or form stops and the whole expression produces true. If all the exp expressions produce false, then the entire or produces false.
Add the primitive operations substring and string-append, so you can write programs in Husky that operate on strings.
Problem 4: Extra credit
Get a little more experience with lexical scope and the management of environments in your Husky interpreter: add the let form to the language.
The syntax of this form is: (let ((var exp) ...) body)
The informal semantics is this: to evaluate a let form, first evaluate all the exp expressions, in the environment that exists outside the let. Then extend the current environment by binding all the var to the resulting values, and evaluate the body form in the extended environment. The result of evaluating the body form is the result produced by the entire let form.
We can put this more precisely, by simply saying that a let form produces exactly the same thing this does: ((lambda (var ...) body) exp ...). (Well, in Husky, you would use a fun instead of lambda...)
(fun (a b c) (let ((discriminant (sqrt (- (* b b) (* 4 a c)))) (two-a (* a 2)) (neg-b (- b))) (list (/ (+ neg-b discriminant) two-a) (/ (- neg-b discriminant) two-a))))
(You can read up on let in the Racket documentation—