Wiki: Elm - FP Web Dev

This article is part of my personal wiki where I write personal notes while I am learning new technologies. You are welcome to use it for your own learning!

What is Elm?

Elm is a functional programming language used to build web applications which transpiles to JavaScript.

Why Should You Care About Elm?

Elm provides significant advantages over JavaScript:

Increased reliability: The Elm compiler catches common errors that happen in JavaScript like those caused by typos or type coertion, etc, at compile time. This translates in having no pernicious and hard to spot runtime exceptions, since these errors will prevent your code from transpiling.

Great developer experience: The Elm compiler produces awesome error messages that help you

The Elm compiler will check these type annotations and make sure that they are followed within your code. This gets more interesting when you can define your own types through type aliases:

typealiasSearchResult={id:Int,name:String,stars:Int}

Which then you can reuse across your codebase:

model={query:String,results:ListSearchResult}

A common type in Elm would represent a message within the Elm architecture:

typealiasMsg={operation:String,data:Int}

We can also use type annotations to represent functions:

add:IntInt->Int-- takes two ints and returns yet another int

For instance, the Elm Architecture view could be seen as follows:

view:Model->HtmlMsg-- view is a function that takes a Model as argument-- and returns an Html of type Msg (whose events trigger messages of type Msg)-- this is essentially generics

You can also use type annotations to denote higher-order functions:

prependprefixword=prefix++wordprepend:string->string->string

An to denote union types, types defined as the union of other types:

typeBool=True|FalsetypeOrder=Ascending|Descending-- Union types can also include generic typestypeColumnOrder=AscendingString|DescendingString-- Which gets useful to describe messages in the-- Elm architecturetypeMsg=DeleteByIdInt|UpdateInt|SearchString

Elm Data Structures/Collections. Records, Tuples and Lists

Records

A record is hash map or dictionary that is immutable. You define it like this:

record={name="rusty iron sword",weight=10,length=1.2}-- you can access its properties using dot notationrecord.name=="rust iron sword"

Records support a similar feature to Object spread operator in JavaScript to update an existing record with new information (which results in a new record):

-- creating a new record with all the properties from sword and a new name "Krull"newSword={sword|name="shiny iron sword"}

Tuples

A tuple is a collection of unnamed items that can have any type and is immutable:

tuple=(1,"and",2)-- you can use tuple destructuring to access the elements within a tuple(first,and,second)=(1,"and",2)first==1

Lists

A list is a collection of items with the same type that is immutable (like an immutable array):

[1,2,3]

Elm lists have interesting functions to work with collections. For instance a filter function:

isOddn=n%2/=0List.filterisOdd[1,2,3,4,5]==[1,3,5]-- this is equivalent toList.filter(\n->n%2/=0)[1,2,3,4,5]==[1,3,5]

And the map function:

List.map(\n->n*3)[1,1,1]==[3,3,3]

All these operations have no side effects, that is, the don’t change the original list but create a new one with the desired changes.

Elm Special Features

Partial Application

All functions within Elm are curried which allows us to use partial application to our hearts content:

The Elm Development Environment

The Elm Package Manager

Elm and Browser APIs

A Note on Error Handling

Elm doesn’t throw runtime exceptions. How does it then let you handle runtime errors? Instead of throwing exceptions Elm provides the Result and Maybe types.

The Result type is a wrapper around an operation that can go well or result in an error:

-- pseudocodetypeResult=OkallThingsGood|ErrsomethingBadHappened

For instance, the String.Int function lets you parse Strings into integers. This operation can fail whenever we try to parse a string that doesn’t contain an integer:

String.Int"42"-- Ok 42String.Int"Cucumber"-- Err "Cucumber is not an Int"

In order to be able to use the actual value within the Result type we need to take into consideration the possibility of an error happening which guides you toward writing less error-prone applications. A special case of Result is the Maybe type reserved to represent when a function may not return a value:

-- pseudocodetypeMaybe=JustaValue|Nothing

For instance, we can use List.head to get the first element of a List. However, a list may be empty in which case we wouldn’t be able to get nothing. Instead of returning null or undefined like JavaScript could the List.head will return the Nothing type:

List.head[1,2,3]-- Just 1List.head[]-- Nothing

Elm, DOM and Virtual DOM

Elm provides a series of functions that allow you to model the browser DOM which result in a virtual representation of the DOM or VDOM. This is how it looks:

Parsing JSON in Elm

Making AJAX requests in Elm

TODO: complete this section

Debugging

The Debug.log function is useful when debugging your code as it allows you to print arbitrary information into the browser console.log. It returns the same value that you pass in so you can use it in the same spot as an actual value within your programs:

Would you like to receive more articles like this one on programming, web development, JavaScript, Angular, developer productivity, tools, UX and even exclusive content like free versions of my books in your mailbox? Then sign up to my super duper awesome inner circle.

Did Ya Know I've Written Some Books?

I have! The JavaScript-mancy series is the lovechild of three of my passions: JavaScript, writing and Fantasy. In the pages of each one of the books of the series you’ll find a breadth of JavaScript knowledge, delivered with a humorous and casual style of writing and sprinkled with Fantasy at every turn.

They are the weirdest and quirkiest JavaScript books you'll ever find. There's nothing out there quite like it.