CS 360
Winter 2015
Programming Language Concepts
Tuesdays, Thursdays 14:00-15:20
University Crossings 151
Instructor: |
Geoffrey Mainland mainland+cs360@cs.drexel.edu University Crossings 106 |
Teaching Assistant: |
Brian Lee bl389@drexel.edu |
In this assignment, you will implement the $\While$ language from lecture.
Before you attempt the homework, be sure you are using our version of GHC. See the GHC guide.
You must implement the functions as specified. You may write other helper functions and define test data in your file, but you may not change the functions’ names or the number or order of arguments.
We have provided you with a shell for your solution here. Please extract this tarball
in your ~/cs360/git
directory and immediately commit the resulting hw7
directory. You can do this as follows:
$ cd ~/cs360/git
$ wget 'https://www.cs.drexel.edu/~mainland/courses/cs360-201425/homework/hw7.tar.gz'
$ tar xf hw7.tar.gz
$ git add hw7
$ git commit -m "Initial check-in for homework 7."
Your changes should be made to the files we have provided as described in each problem below. We have included a non-functional version of every function you must write, so you can also grep the source we have to provied to find the function we have asked you to implement.
We have included several tests for you. You may run these tests by executing the
command make run-tests
in your ~/cs360/git/hw7
directory. Code that does not
compile will receive a zero.
Your code must run on tux
under the version of ghc
that we provide.
Be sure to commit your work to the repository.
This assignment is worth 50 points. There are 51 possible points.
Unlike in lecture, where we represented the interpreter’s state as a function from variables to integers, the code for this homework represents the interpreter’s state as an association list of variables and integer values.
You may notice that we have added a new form of statement, $\mbox{out}~ a$. This statement causes the program to output the value of the arithmetic expression $a$. You can safely ignore this new form of statement until you do Problem 3.
We have included the definition of the $\While$ language here for your convenience.
Complete the definition of the function sSem
, the Haskell implementation of
the semantic function $\S$, in the file Interpreter.hs
.
Recall from lecture that the meaning of a statement in the $\While$ language is a state transformer, that is, a function from state to state.
Modify your interpreter so that it uses a monad. We recommend you read and understand the code given to you; Problem 3 requires that you modify the monad to add additional functionality.
You may want to review the LYAH sections on
We have provided a partial implementation in the file MonadicInterpreter.hs
;
you must complete the definition of sSem
. Your new implementation should be
very similar to the implementation you completed for Problem 1. Look at the
monadic implementations of aSem
and bSem
for inspiration.
What follows is an explanation of the code for the monadic interpreter. You don’t need to understand all of the details to complete Problem 2, but understanding the details will certainly help.
Here is the definition of the State
type that the monadic interpreter uses.
That is, State
is just an association list of variables and integers.
Here is the definition of the I
monad.
You will often see the term “monadic computation.” A monadic computation in I
has type I a
for some a
. For example, I Int
is the type of a monadic
computation in I
that computes an Int
.
The declaration of I
defines a new type constructor, I
, that takes a single
type argument. It also defines a new data constructor, also named I
, that
takes a single argument, which has type State -> (a, State)
. Finally, it
defines a function runI
with type I a -> State -> (a, State)
.
Computations in the I
monad need access to state, which is the list of current
variable bindings. How can we take a pure value, like 3
, and convert it to a
computation in the I
monad? A pure value doesn’t need access to any state, so
we can convert 3
to a stateful computation like this:
The computation threeComp
returns its input state unchanged.
Recalling that $
is just function application, we could have defined
threeComp
this way.
If we look at the definition of the Monad
instance for I
, we see that
return
is the function that “injects” a pure value into the I
monad; in
fact, we could have defined threeComp
this way
Recall that the type of return
is a -> m a
. Since we are defining a Monad
instance for I
, in our case m
is I
. Also recall that the type of (>>=)
,
pronounced “bind,” is m a -> (a -> m b) -> m b
.
What does (>>=)
do? It takes a computation in the I
monad, of type I a
,
and a function of type a -> I b
, and binds the result of the computation
to the input of the function. How does it work? Let’s look at its definition
above. First, it runs the computation comp
by giving it the current
state. This produces a value, x
, and a new state, s'
. Then we need to call
f
, passing it the argument x
, to get a new computation. Finally, we run this
computation with the new state s'
.
In this problem you will add support for output to the $\While$ language. Previously, we defined the meaning of a statement to be a state transformer—a function from state to state, where state is represented as an association list of variables. Now we are going to define the meaning of a statement as a function that takes a state and returns a new state and a list of output values. This is similar to the “debuggable function” example from class, but instead of strings, we are producing lists of integer values.
We have provided a partial implementation in the file OutputInterpreter.hs
;
you must complete the definition of sSem
and the definition of Monad
instance for I
. You must also answer the questions at the bottom of this
problem in a comment in the file OutputInterpreter.hs
.
The new definition of I
is as follows:
Here is the partial definition of the new Monad
instance for I
. Running a
computation now produces a value, a list of outputs, and a new state. When
we run two computations one after the other using (>>=)
, we need to append the
two outputs using (++)
.
You must complete the definition of return
, which turns a pure value into a
computation. A pure value should become a computation that doesn’t modify the
state, i.e., passes it through unchanged, and does not produce any output.
Note the changes you had to make to the sSem
function from Problem 2 to get it
to work with the new monad. Now imagine that you had to modify the interpreter
from Problem 1 to keep track of output values. Would that have required more
modification? Why or why not?
How long did it take you to complete each problem? Please tell us in a comment in each of the files you submit. You must tell us how long each problem took you to receive the point.