In this article I’ll write a simple Bayesian Calculator using Elm.
Link to final project – Bayesian Calculator – Source Code
Create a directory for your project.
cd into it.
Run “elm-make” to initialize a new elm project.
Install some packages for working with web:
elm-package install “evancz/elm-html”
elm-package install “evancz/start-app”
start-app takes care of some application wiring,”setting everything up so you can focus entirely on writing your app”
If you open elm-package.json, you will see that the packages, which we just installed, were added to “dependencies” node.
I’ll use npm and gulp to manage my build. Also, I’m using bootstrap (cause css is hard)
npm init
npm install bootstrap –save-dev
npm install gulp –save-dev
npm install gulp-elm –save-dev
npm install gulp-rename –save-dev
The last piece of setting up is gulp. In the script, I just combine all css and js into bundles and copy them to dest folder.
We’re ready to start writing our app.
Create Calculator.elm. This is where our code will go.
Create Calculator.html. This will encapsulate resulting JavaScript file from Elm. Since I’m writing a full-screen application, all we have to do is add this to the script block:
var app = Elm.fullscreen(Elm.Calculator);
Now, to the application code.
Our model is quite simple – consists of four string fields related to four input fields on the form.
We have three inputs on the page – all encapsulated inside entryForm:
entryForm : Address Action -> Model -> Html entryForm address model = div [ class "form-horizontal" ] [ formGroupItem (priorProbabilityItem address model) , formGroupItem (hitRateItem address model) , formGroupItem (falseAlarmItem address model) , formGroupItem (resultItem address model) ]
formGroupItem is simply a method to produce another div with a class of “form-group”:
formGroupItem : List Html -> Html formGroupItem body = div [ class "form-group" ] body
body in here is just a list of Html elements that we are passing to our div.
Let’s look at one of the inputs:
priorProbabilityItem : Address Action -> Model -> List Html priorProbabilityItem address model = [ label [ for "priorProbability", class "col-md-3 control-label" ] [ text "Prior Probability" ] , div [ class "col-md-9" ] [ input [ type' "text" , placeholder "0.00" , value model.priorProbability , id "priorProbability" , autofocus True , Utils.onInput address UpdateInitialProbability ] [] ] ]
We have a label and a div with an input which maps to priorProbability field in our model.
Every time a user enters something we react to it by addressing UpdateInitialProbability action:
update : Action -> Model -> Model update action model = case action of ... UpdateInitialProbability probability -> { model | priorProbability = probability } ...
In the code above we are updating our model with the new value that a user entered for priorProbability.
We have the same logic for all of the other input fields.
Every time a model changes, we try to show the Bayes calculation result:
resultItem : Address Action -> Model -> List Html resultItem address model = [ label [ for "bayesResult", class "col-md-3 control-label" ] [ text "New Probability" ] , div [ class "col-md-9" ] [ span [] [ text (bayesResult model) ] ] ]
bayesResult is responsible for generating new probability. If some input is invalid, we just don’t display anything. Sure, validation could be a little more sophisticated, but we’re just trying it out.
While in development, make sure to run elm-reactor and gulp in the command line – open two tabs or windows (depending on your console app) for each one and just run “elm-reactor” in one, and “gulp” in another.
In order to see your app in a browser, go to http://localhost:8000/dest/Calculator.html
Every time you save your elm file, it should update the js files in the dest folder. You still have to refresh the browser to see the changes. I haven’t quite figured the auto-refresh part with gulp and elm.
If you want to see the build errors, they should show up in the console, which runs gulp command. Alternatively, if you use Sublime, press Ctrl + B to build it and all errors should show up directly in Sublime.