Elm is pure functional programming language

While preparing for my presentation on ‘Introduction to Elm’, I was trying to prove Elm is a true functional program by showing this below

add: Int –> Int –> Int

add x y =

   x + y

In the above example, add function is pure, for a given input add function always create the same output. So calling Add 2 3 will always return 5. It does not have anything of global scope or side effects. So if I were to introduce a global variable Elm will through a compiler error. I was expecting the following code to produce a compiler error

num: Int

num = 10

add: Int –> Int –> Int

add x y =

    num + x + y

Elm did not complain and it worked. So if I were to pass add 2 3 and the result will be15. So in my mind because of the function depends on outside variable num and someone can change num from outside  the add function is not pure and thus Elm is not functional programming language.

So I posted the question in Elm Slack Channel and @mfeineis answered “Elm is pure and num is immutable”, then it hit me. I assumed few things as a normal imperative programmer would. The num is a variable and it can be changed easily but in functional programming num is not a variable and there is no concept of variable in Elm. So you can’t change the value of num. With that knowledge if you were to look at the function, the function name  is incorrect, it should reflect the proper intention of the function and it should be ‘addnumwithxandy’.

@jessta reply summed up the answer “ `num` and `10` are interchangeable because Elm is ‘referentially transparent’. There’s no difference between a value and a variable containing that value.”

For the people I owe an explanation, hopefully this blog helps and for those helped me in slack channel, big thanks.

Advertisements

Working with backend services in Elm

Before we go past building trivial solution, we need to understand one more concept in trivial example scenario. How do we go about making backend calls? More preciously how to connect and work with API calls.

We will start out with looking at the final result and then we will go about building them. We are building a very simple application which will show the current market value of bitcoin. When you start the application you will see the following screen

image

The screen shows the the initial data of 0. On pressing ‘Get Data’ button, the application will make an API call to “https://api.cryptonator.com/api/ticker/ltc-usd”  url, and display the result as it is in the screen.

image

It does not show the value instead it just displays the whole JSON payload as it is. For our API call discussion we do not need to worry about how to parse JSON and other things, which we will discuss at a later time.

(It will be interesting to come back after couple of years and check the value of bitcoin again 🙂 )

Let’s start building the application without api call first to get the basic screen shown.

First Model:

type alias Model =
     { rate : String
     }

initData : Model
initData =
     { rate = “0”
     }

We have just one field in the model record, which we kept is as String for the sake of simplicity.

To get started we create the update section with

type Msg
     = GetData

update : Msg -> Model -> Model
update msg model =
     case msg of
         GetData ->
             dummyData

As you can expect, when a user clicks ‘GetData’, the GetData message fired by html. That is the only event we needed for the application right now. The action event on GetData does nothing but return a dummy data. It is not making a API call yet.

View is simple and straight forward. One label to show the rates and another button which initiates the GetData message.

view : Model -> Html Msg
view model =
     div []
         [ h3 [] [ text (“Current rate = ” ++ model.rate) ]
         , button [ onClick GetData ] [ text “Get Data” ]
         ]

main =
     Html.beginnerProgram { model = initData, view = view, update = update }

When you run the code first time, it will show the init data with 0.

image

On clicking GetData, it shows the dummy data as expected.

image

You can find the whole base code here in the Gist.

Time to add API call. There is one concept in here will look odd but it is easy to understand. Before we go to API call, I want to go one more time how html and our code interact.

view: Model –> Html Msg

update: Msg –> Model –> Model

In the above code snippet, the view takes the model and creates Html which is capable of creating Msgs (like onClick or onInput). What goes in creating the message is hidden inside the Html module and we do need to worry about, all we need to know is, when some user action happens, Msg will be triggered and ‘update’ function will be called immediately to act on it. 

Now the same way, let’s think about API call, when we make API call we need to wait for the call to complete and up on  completion, we need to modify the model and change in the model will update the view. Very simple. One difference between the button click event and the API event is that when API is called, there is a possibility the call might fail. So the result could come back as either successful (Ok resultValue) and the value or it could comeback with Error (Err _) with error message. So we need to handle both the scenarios in the code on completion of the API call.

Let’s recap what we discussed so far

  • We need to treat API call similar to Html event calls
  • We need a mechanism to fire a message on completion of API call
  • On completion we need to test for successful execution of API and error scenario

It seems there is a lot but not really. Let’s take baby steps and grasp the concept. To make API calls we need to install Http module. Once installed let’s write the code to make the API call. To make a Http Get we can use

Http.getString uri

this will make a call and gets string response from the uri. Simple. We could create a function which does it. But we have a problem, this return string and we need to wait for it complete. We need to modify this some how so that, on completion it generates a message which we can act on when we get it. How do we go about doing it?

It is solved by Http.send function. Http.send function, will return a message on completion of a http request. So we can modify the previous statement to something like the following

Http.send HttpDataComplete (Http.getString url)

Http.Send is a command, which will initiate the Http.getString and on completion it will trigger HttpDataComplete event/msg. So if we were to write a function to do this task it will be something like this

httpGetData: Cmd Msg

httpGetData which does not get any input data will generate a command which is capable of generating messages. Now let’s look at the implementation

httpGetData =

     Http.send HttpDataComplete (Http.getString “https://api.cryptonator.com/api/ticker/ltc-usd”)

We have a function to get data. Now we need to call this function when Get Data button pressed.

Our current update function signature is

update: Msg –> Model –> Model

This reads, update function takes Msg and current state of the model and generate new model. But the changes we made, when some one presses GetData button, we not only generate model but also create a command which could create msg (like out view defintion view : Model –> Html Msg). So our update definition now changes to

update: Msg –> Model –> (Model, Cmd Msg)

With that definition, when a user clicks on ‘GetData’, we need to call the httpGetData function. We will do it something like the following

case msg of

     GetData –>

            (model, httpGetData)

if you look at the return state here, it following the signature of (Model, Cmd Msg).  Now that we made the call how are we going to handle the response from get data call?

When you make a API call, you can get either a success or failure. On success, we change the rate value with result value. On failure, we need to reset it to initial data. In Elm we have something Result which helps with this situation. Anytime when we perform an operation which could result in success or failure then we need to use Result. With that, when Http make HttpDataComplete message, it will come back with result. So we need to modify the signature of our message to represent this scenario

HttpDataComplete (Result Http.Error string)

Now in our update function, when we get HttpDataComplete, we need to check for success and failure in the case

case msg of

     HttpDataComplete (Ok data) –>

     HttpDataComplete (Err _) –>

The second (Err _) parameter means, when you get an error with any value perform that function.

Now we know we need to handle both the scenario, what should be do when API calls comes back successful? All we need to do is modify the rate value in the model with incoming data. Now if you remember, our update function expect the second parameter to a command generating function. In our case after updating the model, we do not need to initiate any commands so all we need to pass is Cmd.none. On error reset the data model to initial data and same as success scenario, pass is no commands. So here is the completed update function

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
     case msg of
         GetData ->
             ( model, httpGetData )

        HttpDataComplete (Ok val) ->
             ( { model | rate = val }, Cmd.none )

        HttpDataComplete (Err _) ->
             ( initData, Cmd.none )

We are not done yet, two more things we need to do. When we move to this model of program, it is possible you might want to load data from backend API on page load that means we need to call that function without any program intervention. To accomplish that, we need to move to a different helper function called ‘program’ in Html.

Html.program takes different set of parameters

  • First parameter is initial data. It includes the initial model and any function that need to be executed to load data from back end. In this example, we are not expecting to load any data from API on load. So the values (model, Cmd.none)
  • Second is view and there are no changes to it
  • Third parameter is update function. No change there.
  • Final parameter is subscription. For Http example there are no subscription so we are going to create a dummy subscription to satisfy the signature in a minute

subscription : Model -> Sub Msg
subscription model =
     Sub.none

You can find the final source code for this here in this Gist.

Unit testing in Elm

Elm shines in help build applications which does not crash in production.  With static typing, functional nature and compile time verification the odds of breaking Elm application is low. That is been said, it does not give you pass not to write tests. I talked in length over time about TDD and why TDD is the best way to build applications. Here are two important things you need to know about TDD

  1. Help build highly maintainable code because the tests guarantee you will not break any other part of the application.
  2. TDD when done right, will allow you to write very little code to meet the expectation of the requirements. Less code you write less bugs you introduce.

Since everything in Elm is function, we can test everything.

To setup, we need to install elm-test package by running

elm package install elm-community/elm-test

This will install all the packages required for building unit tests. Once install, let’s initialize project structure for creating unit tests by running following in application root directory

elm-test init

This will create a test folder and create a simple test with a ‘todo’ and install associated project dependencies. So before you do anything, run

elm-test

in the root directory and it should run the default tests and come back with following message

elm-test 0.18.8
—————

Running 1 test. To reproduce these results, run: elm-test –fuzz 100 –seed 5741
56140

TEST RUN INCOMPLETE because there is 1 TODO remaining

If you get the above message then all setup and ready to start write testing. If you have problem setting up the test environment, send me a message.

I love to do my tests using BDD model and fortunately, there is a package for that which makes it very readable. When ‘elm-test init’ ran it created a sub directory called test to write all your tests. Switch to the test directory and install the BDD package

elm package install rogeriochaves/elm-test-bdd-style

Let’s get our feet wet with nothing fancy but just do normal assertions to see how they all connected. Create a a file in test subdirectory of the project root directory. Create an elm file, I called it ‘SayMyNameTester.elm”

Let’s start importing the required packages for testing

import Test exposing (..)
import Expect exposing (..)
import ElmTestBDDStyle exposing (..)

basictest : Test
basictest =
     describe “Tests Basic Assertions”
         [ test “1. can test equal traditionally”
             (\() -> Expect.equal “test” “test”)
         , test “2. can test equal traditionally with infix” <|
             \() -> Expect.equal “test” “test”
         , it “3. can test equal with bdd with infix” <|
             expect “test” to equal “test”
         , it “4. can test equal with bdd more readable”
             (expect “test” to equal “test”)
         ]

The above test is nothing but doing a simple assertion and “test” equal to “test” which results in true. But it was written in four different ways to show different ways of writing it and pick the one you are comfortable with and go with it.

When you run Elm-Test at the project root directory, it will executes all the files in the test directory with Test/Suite function definitions. In our code we have just one function definition with Test signature, which is basictest.  So running the Elm-Test should result something like the following

image

Let’s walk through each of the tests to understand what is the different

Test 1:

test “1. can test equal traditionally”
             (\() -> Expect.equal “test” “test”)

For starters, test function, takes a string and an Assertions and return a Test. The first parameter is “1. can test equal traditionally” a string. The second parameter is the Assertions “(\() -> Expect.equal “test” “test”)” which returns a Bool. For the people who are coming from traditional programming language,

\() –>

represents an anonymous function. Also the second parameter is enclosed in () so that it gets executed to return Test result.

Test 2:

This is exactly same as Test 1 except we replaced the () with an infix notation backward pipe operator <| Backward pipe and forward pipe operator (|>) or interesting operators of the functional programming, which got its roots from Unix world. You can read more about it here.  For me this gives more readability than using (). When you compose lot of operations, when using () might make it bit hard to read. So I prefer to use pipe operator

Test 3 & 4:

Test 3 & 4 are similar variations of Test 1 & 2 except, 3 & 4 is written in BDD style. Compare to 1 & 2, 3 & 4 are readable.

My recommendation to use the BDD style option 3 for more readability. Especially when you are building large code base, help the people who are coming after to do their job easier by writing readable tests. They will thank you for doing it.

I was going to write how to write a unit test for our project but I found a great video of Andy Balaam, who walks through the whole unit testing. It is worth checking out.

Reference:

https://medium.com/@_rchaves_/testing-in-elm-93ad05ee1832

https://www.linkedin.com/pulse/single-page-web-apps-elm-part-three-testing-structure-kevin-greene

Setting up Elm development environment

Now that we know some of the core fundamentals and things that make up Elm, let’s start learning by coding. For that, we need to setup the development environment first. It is simple and easy.

I was going to write step by step instructions on how to setup Elm for Atom editor but found this great Git repo. This has all the information needed to setup. Few of things you need to know as you go through them

  • Where ever, it say ‘which’ replace with ‘where’ for Windows
  • If you are using Atom if for some reason something not working, restart Atom
  • linter-elm-make required elm-make.exe, if you are in Windows, make sure when you paste the location of the elm-make, put the whole path and the file name in double quotes like the following

“C:\Program Files (x86)\Elm Platform\0.18\bin\elm-make.exe”

  • When you start a new Elm file, the Elm language may not work, for that make sure you install elm-package. Atom will complain about missing json file. Execute the following in the command prompt

elm-package install

If you face any problem following the git repo, let me know I will try to help

Anatomy of Elm

When I started learning Angular once I understood the angular life cycle, learning Angular was easy. So I would like to do the same here for Elm also. Elm’s anatomy is simple. In my previous blog, I mentioned what are all the components constitute elm application.

Elm application has three components, model, view and update along with the main entry point. Now let’s look at how the whole thing work.

All elm application starts with entry point main. Elm comes with great bootstrap for us get started call beginnerProgram, which hides all the wiring to connect all the parts. So to get started our main entry point will be something like the following

main =

     beginnerProgram (model = data, view = view, update = messageHandlers}

Here we call the main entry point with the three components, model, view and update.

The flow of control

clip_image001

  1. On program entry, Elm reads the model data to build the view

2. View generates HTML to render with the data from the model

3. User interacts with view on each user interaction, message gets generated.

4. Messages passed to update function. Update look at the incoming messages and create new instance of the model. (It is functional program, model is immutable)

5. The new model will trigger the creation of new view and the loop repeats.

That is it.

Elm – Basic Architecture

Before you go head first into building, it is good understand the basic architecture of Elm. Most of the application follows one of the MV* pattern. Elm also follows the pattern in a different way. Elm has three distinct parts in the application

Model: As the name suggests the state of the application. You data model. Model defines and holds the current state of the application.

View: This holds the visual representation of the application, HTML, Think of this as HTML template.

Update:These are the events which triggers change in model state which triggers change in view.

When you look at Elm application, you potentially will have view, model and updates all in single Elm file. During deployment, elm will compile this file and spit out, HTML and Javascript.

With the above architecture, one would always need to have entry point to the application and that is represented by ‘main’. We will see more details how they all fit together tomorrow.