The purpose of this lab is to help you understand how to use Functional Reactive Programming(FRP) in the Elm language to create a GUI. It is also to expand your idea of what a type can be by using Algebraic Data Types (ADTs).
Make sure that you have the Elm compiler installed. Get it at https://guide.elm-lang.org/install/elm.html.
In order to make tic-tac-toe, you will need to implement the following types:
… and the following functions:
init :: Model
update :: Msg → Model → Model
view :: Model → Html Msg
Whenever writing Elm code (or any code, for that matter), it is a good idea to write many small functions with a specific purpose and then build more complicated functions from them. That said, you should feel free to make helper functions to break up the code needed for these required functions.
Elm is a “delightful language for reliable webapps”. As such, it was made with the intent for it to be used as a front-end development platform. We recognize that not everyone taking CS 330 will have experience making webapps, so we have provided for you all the boilerplate to make your code work in the browser.
You are provided with 3 files:
index.html, the entry-point for the app
index.css, the stylesheet to make everything look right.
Lab9.elm, the template Elm file that you fill in with your code.
If you open
index.html in your browser it will open a totally white page. That is because in order for the webapp to run,
tic-tac-toe.js. We will create this file by compiling our Elm to JS.
Before we can compile the Elm file into JS, we need to run the
elm init function inside the directory where you put the files. This will create a file called “elm.json” which is necessary for compiling but you will not need to modify.
Now, to compile your Elm project so that it can be viewed in the browser, run the following command:
elm make Lab9.elm --output=tic-tac-toe.js
If you run that command with the code we provided unmodified, it will give you an error because there are unimplemented types and functions. Let's start implementing them.
One useful feature that Elm boasts is helpful and descriptive error messages. The creators' intent was for the compiler to act like a coding buddy. Using what the Elm developers call “Compiler Driven Development”, you can use the compiler error messages to help you get to working code. So do not be afraid to run the compile command to figure out what to fix next.
The first thing you will need to do is create an ADT called
Model will be a type for an object that represents the state of the program. Once you have defined the
Model type, you will then need to implement the
init will return an instance of
Model that will be the initial state of the program. In our case, the initial state of our program is a blank tic-tac-toe board and the player who's turn it is.
Next, create a type called
Msg. When the user interacts with the webapp in some way (clicks a button, in our app) the runtime will be sent an instance of
Msg should carry information about the interaction.
Once you have a definition for
Model you can start implementing the
update function. This function will will be called by the runtime whenever it receives a
Msg which is whenever the user pushes a button.
update will be passed the
Msg instance and the current
Model from the runtime and will return a new model. For example, the runtime may receive a message saying that the X-player clicked on the square at the top-left. The
update function should then return a
Model that reflects the appropriate change: the top-left corner is marked with an X and it is now the O-player's turn. Bear in mind that you are not performing any mutation of variables, only returning a new version of the
You will then need to finish the implementation of the
view function. This function's purpose is to take the current model from the runtime and produce a user interface of HTML elements based on that model. HTML elements are made in Elm by calling functions imported from the
Html module that take as arguments a list of properties and a list of HTML elements. Notice that these elements of type
Html Msg. This tells the runtime that these UI elements cary with them the capability of sending messages of type
Msg back to the runtime.
Some of this function has already been implemented for you and you do not need to modify it further. There are two parts of it that have parentheses with a comment saying “Your code here”. In the first set of parentheses, write an expression that evaluates to a
Html Msg instances that represent the the tic-tac-toe board. This should effectively produce a game board in the UI that reflects the
model that was passed to the
view function. I would suggest you make the parts of the board that are clickable (blank spots) into buttons. The code to make a button that sends the message
SomeMsg with the text “I am a button” would look like this:
button [ onClick SomeMsg ] [ text "I am a button" ]
After a button has been selected it should be replaced with a
div that has some text saying which player selected that tile. The code to make a div with some text inside is like this:
div  [ text "I am a div" ]
The next thing to modify inside of
view is the part that says “\*TODO\*: Place whose turn it is here”. In place of that string, put a string that says whose turn it is based on the passed-in
Then, after that there is a button with the text “Reset” and the
onClick attribute is left blank. Fill that part in with some that evaluates to a
Msg that should be sent to the runtime when the reset button is clicked.
When you're finished, your app should show a 3×3 grid of buttons, a piece of text that says whose turn it is, and a reset button. When a button on the grid is pushed it should be replaced with an X or O depending on whose turn it was when the button was pushed, and the text should change to show that it is now the next player's turn. When the reset button is pushed, the grid should go back to its start state and the turn should go back to the first player. NOTE: You do NOT have to check if a player has won the game.