CS 550
Spring 2015
Programming Languages
Thursdays 18:30-21:20
Korman Center 104C

Geoffrey Mainland
University Crossings 106
Teaching Assistant:
Mark Boady
Warning! This material is for an old version of the course.

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 ~/cs550/git directory and immediately commit the resulting hw4 directory. You can do this as follows:

$ cd ~/cs550/git
$ wget 'https://www.cs.drexel.edu/~mainland/courses/cs550-201435/homework/hw4.tar.gz'
$ tar xf hw4.tar.gz
$ git add hw4
$ git commit -m "Initial check-in for homework 4."

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 ~/cs550/git/hw4 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.


The $\While$ Language

We have included most the definition of the $\While$ language here for your convenience. You will need to refer to the lecture slides, the text, and/or your notes for the operational semantics of statements.

Figure 1: BNF Grammar for the $\While$ language.
Figure 2: Semantic function for determining the meaning of a $\While$ arithmetic expression.
Figure 3: Semantic function for determining the meaning of a $\While$ boolean expression.

Problem 1: Implement operational semantics (10 points)

Complete the definition of the function sStep, the Haskell implementation of the operational semantics for the $\While$ language, in the file Interpreter.hs.

You may choose to implement either the small-step or the big-step semantics, but you may not change the type signature of sStep. Think carefully about your choice.

Problem 2: Make your interpreter monadic (20 points)

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 sStep. 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.

type State = [(Var,Z)]

That is, State is just an association list of variables and integers.

Here is the definition of the I monad.

newtype I a = I { runI :: State -> (a, State) }

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:

threeComp = I (\s -> (3, 2))

The computation threeComp returns its input state unchanged.

Recalling that $ is just function application, we could have defined threeComp this way.

threeComp = I $ \s -> (3, s)

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

threeComp = return 3

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.

instance Monad I where
    return x   = I $ \s -> (x, s)
    comp >>= f = I $ \s -> let (x, s') = runI comp s
                             runI (f x) s'

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'.

Problem 3: Add support for output (20 points)

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 sStep 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:

newtype I a = I { runI :: State -> (a, [Z], State) }

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 (++).

instance Monad I where
    return x   = ...
    comp >>= f = I $ \s -> let (x, o1, s1) = runI comp s
                               (y, o2, s2) = runI (f x) s1
                             (y, o1 ++ o2, s2)

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 sStep 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?

Problem 4: Homework Statistics (1 point)

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, expressed as a quantitative measure of time, to receive the point.