TDA 452
DIT 142
HTÂ 2017

# Functional Programming 2017 Lab 4 Graphical Calculator

In this Lab Assignment, which is one of the options for Lab 4, you will design and implement a very simple graphical calculator. For the graphical part we will use the Haste compiler which is able to compile Haskell code to an HTML file which can be run in a web browser. See this introduction to Haste on how to get started with Haste.

### Hints

Some assignments have hints. Often, these involve particular standard Haskell functions that you could use. Some of these functions are defined in modules that you have to import yourself explicitly. You can use the following resources to find more information about those functions:

We encourage you to actually go and find information about the functions that are mentioned in the hints!

## A Graphical Calculator

The graphical calculator will be implemented as a web page that might look like this:

The page consists of a drawing area, and a text entry field below it. The user can type mathematical expressions in the text entry, which, after pressing the Draw graph button, will be graphically shown on the drawing area.

The lab assignment consists of two parts. In Part I, you will implement the parts of your program that have to do with expressions. In part II, you will implement the graphical part of your program.

## Part I

In this part, you are going to design a datatype for modelling mathematical expressions containing a variable x. For example:
• 3*x + 17.3
• sin x + cos x
• sin (2*x + 3.2) + 3*x + 5.7
In other words, an expression consists of:
• Numbers; these can be integers as well as floating point numbers
• Variables; there is only one variable, x
• Operators; for now it is enough with + and *.
• Functions; for now it is enough with sin and cos.
You will also implement a number of useful functions over this datatype.

Put the answers for Part I in a module called `Expr.hs`.

### Assignments

A. Design a (recursive) datatype `Expr` that represents expressions of the above kind.

You may represent integer numbers by floating point numbers; it is not necessary to have two different constructor functions for this. Your data type should be designed to make it easy to add more functions and more binary operators to the language.

B. Implement a function
`showExpr :: Expr -> String`
that converts any expression to string. The strings that are produced should look something like the example expressions shown earlier. Use as little parentheses as possible, but consider that we want to be able to read an expression back without loss of information, as discussed in assignment D and E below.

It is not required to show floating point numbers that represent integer numbers without the decimal part. For example, you may choose to always show 2.0 as "2.0" and not as "2". (But you are allowed to do this.)

If you want to, you can from now on use this function as the default show function by making `Expr` an instance of the class Show:

```instance Show Expr where
show = showExpr```
But you do not have to do this. (Also: see the hint on testing below!)
C. Implement a function
`eval :: Expr -> Double -> Double`
that, given an expression, and the value for the variable x, calculates the value of the expression.
D. Implement a function
`readExpr :: String -> Maybe Expr`
that, given a string, tries to interpret the string as an expression, and returns Just of that expression if it succeeds. Otherwise, Nothing will be returned. You are required to use an unmodified version of the module Parsing.hs to construct this function. See the lectures from Week 4 on parsing expressions.

The next assignment is about checking that your definition of `readExpr` matches up with your definition of `showExpr`. One could define a property that simply checks that, for any expression e1, if you show it, and then read it back in again as an expression e2, then e1 and e2 should be the same.

However, this doesn't work if there is certain information loss in showing an expression. This happens, for example, if the expressions (1+2)+3 and 1+(2+3), which have different representations in your datatype (and are not equal), are both shown as "1+2+3".

A simple solutions to this problem is to include the parentheses when showing 1+(2+3) and only omit them when showing (1+2)+3. A nicer solution is perhaps to use an equality test that takes the associativity of operators into account (e.g. it considers 1+(2+3) and (1+2)+3 equal). See the function `assoc` in exercise 3B from week 5 for an example of how you could implement this.

E. Write a property
`prop_ShowReadExpr :: Expr -> Bool`
that says that first showing and then reading an expression (using your functions `showExpr` and `readExpr`) should produce "the same" result as the expression you started with.

Also define a generator for expressions:

`arbExpr :: Int -> Gen Expr`
Do not forget to take care of the size argument in the generator.

Make `Expr` an instance of the class `Arbitrary` and QuickCheck the result!

```instance Arbitrary Expr where
arbitrary = sized arbExpr```
`quickCheck` will call `arbExpr` with sizes in the range `[0..99]`, so make sure `arbExpr` produces reasonably sized expressions for testing with this range of sizes.
F. Define a function
`simplify :: Expr -> Expr`
which simplifies expressions so that subexpressions not involving variables are always simplified to their smallest representation, and that (sub)expressions representing x + 0 , 0 * x and 1 * x and similar terms are always simplified. Define (and run) QuickCheck properties that check that the simplifier is correct (e.g. 1+1 does not simplify to 3), and that it simplifies as much as possible (or more accurately: as much as you expect!).
G. Define a function
`differentiate :: Expr -> Expr`
which differentiates the expression (with respect to x). You should use the simplify function to simplify the result.

### Hints

• To design the datatype, you might be inspired by the `Expr` datatype discussed in the lectures in Week 4. Read the slides and look at the example code! It is important that your datatype is simple and elegant; try not to use too many data constructors for example. If two different cases can be effectively expressed using one constructor, then do that.

When designing your datatype `Expr`, think carefully about how you want to express the variable x. You may get inspired by the `Expr` datatype from the lectures, but remember that there is a difference; in your datatype you only have to represent one variable, called x, whereas in the lecture we allowed for several different variables.

• When showing and reading expressions, we have to decide where we allow and require parentheses. Parentheses are required only in the following cases:

• When the arguments of a *-expression use +. For example: (3.1+4.2)*7
• When the argument of sin or cos uses * or +. For example: sin (3.2*x)

In all other cases, you should not require parentheses. For example:

• Allow 2*3+4*5 instead of 2*3+(4*5)
• Allow sin x instead of sin(x)
• Allow sin cos x instead of sin (cos x)
• Allow sin x + cos x instead of (sin x) + (cos x)

Make sure that the above expressions are all parsed correctly by your program!

• For the functions `eval`, `showExpr`, `readExpr`, `arbExpr`, and `prop_ShowReadExpr` also consult the lectures from Week 4, and look at the example code that is provided.

• For the function `readExpr`, to be able to parse floating point numbers (Doubles) and sin and cos, you only have to change the parser for factors.

To parse floating point numbers, make use of the standard Haskell functions `reads` exported as `readsP` in the Parsing module. Use it on the right type (`Double`), and see what happens!

````read "17.34" :: Double`
...
`read "17.34cykel" :: Double`
...
`reads "17.34cykel" :: [(Double,String)]`
...
```
• If you have a hard time understanding the generated counter examples for your property, it is probably a good idea to let Haskell derive the show function for your `Expr` datatype, instead of making your own instance of Show. So, use `deriving Show` on your expression datatype while testing!

## Part II

In this part, you are going to implement the graphical part of the calculator. To do this in a platform-independent way, we will use a web browser for the user interface. Here are two ways to do this:
Using the Haste compiler:

• Installing Haste on the student computers.
• Installing Haste on your own computers. Some observations (November 2017):
• The recommended way to install Haste is to use one of the binary installer packages from haste-lang.org/downloads. The most recent version available for Linux and Windows is 0.6.0.0. For Mac, the most recent version available is 0.5.5.1.

• To install Haste from source, follow the instructions on haste-lang.org/downloads, but note that this only works with GHC 7.10, which is the version you get when you install the Haskell Platform with `apt-get install haskell-platform` on Ubuntu 16.04 and similar Linux systems. If you have Ubuntu 17.x, or if you recently installed the Haskell Platform on Windows or Mac, you probably have a GHC 8.x.

You can read more about how to use Haste in the material for the lecture Haskell in the Browser. That page introduces a number of helper functions which are available in the module Pages.hs. It is recommended that you use this module for your calculator web page. However, you are free to design the web page as you want, and it is not required to use the helper functions.

Using threepenny-gui. (This is option was added in 2017.)

threepenny-gui is a normal Haskell library, so it is easier to install than Haste. But as with Haste, the user interface opens in your web browser, so creating a user interface with threepenny-gui will be very similar to using Haste. We have created a module ThreepennyPages.hs that is similar to `Pages.hs` for Haste, so the introduction to Haste mentioned above might be useful even if you decide to use threepenny-gui.

The graphical interface consists of at least two parts: (1) the drawing area, where the function is going to be drawn, and (2) the text entry field.

The drawing area is a "canvas" element of a certain size (you decide yourself, but let us suppose it has width and height of 300). A canvas has a coordinate system that works in pixels. Here is how it works:

 (0,0) (300,0) (0,300) (300,300)

Perhaps surprising is that y-coordinates are upside down; they are 0 at the top, and 300 at the bottom.

The tricky thing using this canvas to draw our functions is that the coordinate system we are used to in mathematics has (0,0) in the middle, and the y-coordinates are not upside down. For example, the coordinate system for our functions might work like this:

 (-6.0,6.0) (6.0,6.0) (0,0) (-6.0,-6.0) (6.0,-6.0)

So, some conversion is needed between pixels and mathematical coordinates. Note, though, that both coordinate systems are represented using the type `Double`.

The answers for Part II should be put in a module called `Calculator.hs`. It should of course import the module `Expr`.

In this lab you are free to be creative when designing the calculator. But for those who just want to focus on the important stuff, we have prepared a stub program that constructs the web page for you: Calculator.hs. This file makes use of Pages.hs which is mentioned above. If you work with threepenny-gui instead of Haste, there corresponding files are ThreepennyCalculator.hs and ThreepennyPages.hs.

### Assignments

H. Implement a function with the following type.
`points :: Expr -> Double -> (Int,Int) -> [Point]`
The function gets three arguments; points exp scale (width,height):
• An expression exp
• A scaling value scale
• The width and height of the drawing area
The type Point is already defined in Haste, and is just a pair of integers:
`type Point = (Double, Double)`
The idea is that points will calculate all the points of the graph in terms of pixels. The scaling value tells you the ratio between pixels and floating point numbers. The arguments width and height tell you how big the drawing area is. We assume that the origin (0,0) point is in the middle of our drawing area.

For the canvas and function coordinate systems above, we would use 0.04 for the scale (since 1 pixel corresponds to 0.04 in the floating point world, this is (6.0 + 6.0) / 300), and (300,300) for the width and height.

I. Implement the graphical user interface that connects assigments A–F into a web-based graphical calculator.

If you are basing your code on the provided module Calculator.hs, this part only involves completing the function

`readAndDraw :: Elem -> Canvas -> IO ()`
which reads the expression from the given input element and draws the graph on the given canvas.

When the user types in something that is not an expression, you may decide yourself what to do. The easiest thing is to draw nothing.

J. Implement some form of zooming. There are a number of ways to do this. Either the user clicks somehwere on the canvas, and the drawing function zooms around that point. Or there could be a text entry where the scaling factor can be given. Or there could be a slider that the user can drag.

Make sure you also add a way to zoom out after you have zoomed in.

K. Implement a "differentiate" button which displays both the differentiated expression and its graph.

### Hints

To convert back and forth between Ints and Doubles, the following function might come in handy:

```fromIntegral :: Int -> Double
round        :: Double -> Int```
These functions have more general types than the ones given above. For other conversion functions, use Hoogle!

To implement the function `points`, it is probably a good idea to define the following two local helper functions:

```where
– converts a pixel x-coordinate to a real x-coordinate
`pixToReal :: Double -> Double`
pixToReal x = ...

– converts a real y-coordinate to a pixel y-coordinate
`realToPix :: Double -> Double`
realToPix y = ...```

The easiest way to draw the graph on the canvas is to use the function `path`,

`path :: [Point] -> Shape ()`
which makes a curve from a list of points.

Another alternatives (which seems to give smoother curves when there are sharp edges) is to draw the curve manually as a sequence of lines. To do this, you can define a helper function of type:

`linez :: Expr -> Double -> (Int,Int) -> [(Point,Point)]`
The function gets the same arguments as points, only it will calculate the lines that are going to be drawn between the points. So simply create a line (as a pair of points) between each consecutive point generated by points.

The Haste page has several examples relevant for this assignment. In particular:

• The Bouncing Balls example for the use of canvas
• The Echo example for the use of text entries

## Extra Assignments

You may freely extend your solution to include other features, but please do so in a way that does not make it more difficult to understand the code for the parts of the lab described above.

## Submission

Submit your solutions using the Fire system.

Your submission should consist of the following files:

• `Expr.hs`
• `Calculator.hs`

Before you submit your code, Clean It Up! Remember, submitting clean code is Really Important, and simply the polite thing to do. After you feel you are done, spend some time on cleaning your code; make it simpler, remove unneccessary things, etc. We will reject your solution if it is not clean. Clean code:

• Does not have long lines (< 78 characters)
• Has a consistent layout
• Has type signatures for all top-level functions