Remember to follow the pledge you read and signed at the beginning of the semester. For this assignment, you may consult any outside resources, including books, papers, web sites and people, you wish except for materials from previous cs1120, cs150, and cs200 courses. You may consult an outside person (e.g., another friend who is a CS major but is not in this class) who is not a member of the course staff, but that person cannot type anything in for you and all work must remain your own. That is, you can ask general questions such as "can you explain recursion to me?" or "how do lists work in Scheme?", but outside sources should never give you specific answers to problem set questions. If you use resources other than the class materials, lectures and course staff, explain what you used in your turn-in.
You are strongly encouraged to take advantage of the scheduled help hours and office hours for this course.
In this problem set, we provide a working interpreter for the Charme language, which is approximately a subset of Scheme. The interpreter implements the Scheme evaluation rules with state. Your assignment involves understanding the interpreter and making some additions and changes to it. If you are successful, you will produce an interpreter for the language Mesmerize in which the original Fibonacci procedure can be applied to 60 to produce the correct result in a reasonable amount of time.
It defines a procedure meval that takes two inputs: a list that represents a Charme expression and an environment. It outputs the value of the input expression. The initializeGlobalEnvironment() procedure initializes the global environment in the global variable globalEnvironment. We can use the as the second input to meval. You can try some evaluations using meval directly:
This is a bit awkward since the first input is not in the standard Charme notation, but the parsed structure.>>> initializeGlobalEnvironment()
>> meval('23', globalEnvironment)
23
>>> meval(['+', '1', '2'], globalEnvironment)
3
The parse procedure takes a string representing one or more Charme expressions and produces as output a list containing each input expression as a structured list. For example:
Since parse takes one or more expressions and produces a list of expressions as its output, we cannot pass the result from parse direction to meval. If we just parse one expression, we just want to pass the first element of the parse output to meval:>>> parse("23")
['23']
>>> parse("(+ 1 2 (* 3 4))")
[['+', '1', '2', ['*', '3', '4']]]
>>> parse("(define square (lambda (x) (* x x)))")
[['define', 'square', ['lambda', ['x'], ['*', 'x', 'x']]]]
>>> meval(parse("(+ 1 2 (* 3 4))")[0], globalEnvironment)
15
It is a bit awkward to remember the [0] and to pass in the globalEnvironment, so we have defined a procedure evalInGlobal(expr) that takes a string representing one Charme expression and evaluates it in the globalEnvironment:
For example:def evalInGlobal(expr): return meval(parse(expr)[0], globalEnvironment)
>>> initializeGlobalEnvironment()
>>> evalInGlobal("(define square (lambda (x) (* x x)))")
>>> evalInGlobal("(square 4)")
16
>>> evalInGlobal("square")
<__main__.Procedure instance at 0x03C0BE18>
We have also provided the evalLoop() procedure that provides an interactions buffer for Charme.
From the perspective of our shiny new interpreter, a Charme program is really just a string that we parse and evaluate.
When you've done it correctly, you should see output like this:
>>> initializeGlobalEnvironment()
>>> evalInGlobal(charmeFactorialDefinition)
>>> evalInGlobal("(factorial 5)")
120
Hint: Remember that Charme does not support the define shortcut for quickly listing function and their arguments. You must write your answer out longhand with lambda.
>>> initializeGlobalEnvironment()
>>> evalInGlobal("(<= 5 3)")
False
>>> evalInGlobal("(<= 3 7)")
True
You should start by defining a class that represents a cons cell. For example, you might define a Cons class that has a constructor (__init__) that takes two inputs (the first and second parts of the pair), and provides methods for getFirst and getSecond that retrieve the respective parts of the pair.
You must also define a __str__(self): method for your class so that evalLoop and evalToplevelExp will print out Cons sells similarly to how they are displayed in Scheme.
You should get the following interactions in the evalLoop():
Charme> (cons 1 2)
(1 . 2)
Charme> (car (cons 1 2))
1
Charme> (cdr (cons 1 2))
2
Charme> quit
Or the equivalent ones with evalInGlobal:
>> evalInGlobal("(cons 1 2)")
(1 . 2)
Hint: You could use Python's None value to represent null.
After finishing these questions, you should get the following interactions in the evalLoop():
Charme> (define a (list 1 2 3 4))
Charme> (car a)
1
Charme> (null? a)
False
Charme> (cdr (cdr a))
(3 4)
Note that this is the way Scheme prints out lists, and you are encouraged to make your Charme interpreter also print out lists this way. It is acceptable, though, to print out lists in a more straightforward way, so they would be displayed as normal cons pairs. Then, this would look like, (3 . (4 . None)), instead.Charme> (null? (list ))
True
Charme> (cond)
None
Charme> (cond ((> 1 2) 2))
None
Charme> (cond ((> 1 2) 2) ((> 3 2) 3))
3
Charme> (define fibo (lambda (n) (cond ((= n 1) 1) ((= n 2) 1) (true (+ (fibo (- n 1)) (fibo (- n 2)))))))
None
Charme> (fibo 10)
55
To implement memoizing, we need to save the results of all procedure applications in a table. When a procedure application is evaluated, first, we lookup the application in the table to see if it has already been computed. If there is a known value, that is the result of the evaluation and no further computation need be done. If there is not, then the procedure application is evaluated, the result is stored in the table, and the result is returned as the value.
(Hint: review your class notes for non-memoized procedure applications.)
(Hint 2: about five lines should do it. Consider adding an if statement far before the call to meval in mapply.)
pleased = """ What are you most pleased about regarding this course? """
displeased = """ What are you most displeased about regarding this course? """
hopetolearn = """ What did you most hope to learn in this course that we have not yet covered? """