CS 360
Winter 2017
Programming Language Concepts
CS 360-001 Tuesday/Thursday 15:30-16:50 (Rush 9)
CS 360-002 Tuesday/Thursday 14:00-15:20 (Rush 9)
CS 360-003 Tuesday 18:30-21:20 (Science Center 326, 3401 Market)

Instructor:
Geoffrey Mainland
mainland+cs360@drexel.edu
Office: University Crossings 106
Office hours: Mondays 4pm–7pm; Thursdays 5pm–6pm.
Teaching Assistant:
Xiao Han
CLC office hours: Monday 2pm–4pm; Friday 3pm–5pm
Warning! This material is for an old version of the course.

In this assignment, you will implement the $\While$ language from lecture.

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.

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 provided to find the function we have asked you to implement.

Note that source files are located in the src subdirectory.

This assignment is worth 50 points. There are 51 possible points.

Standard homework instructions

Your code must run either on tux or on the course VM using the version of GHC (8.0.1) that we provide.

A solution template is available in the DrexelCS360/homeworks GitHub repository. You should only need to modify the files provided by the template—please do not check in any files beyond those that the template provides.

You can check that your code compiles by typing make in the hw6 directory. If make does not complete successfully, it means your code does not compile. Code that does not compile will receive a zero.

We have included several test for your convenience. Passing all provided tests does not guarantee full credit, but failing tests does guarantee less than full credit. You can run the tests by typing make run-tests in the hw6 directory.

Notes

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
                           in
                             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 your README.md.

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
                           in
                             (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 hw6/README.md. To receive credit, tell us how long each problem took you by giving us a quantifiable number, e.g., 30min or 1h30.