Notes on Elm programming language
Elm is a functional programming language specifically designed for a frontend. Here are short quick notes about its discovery.
Installation and running
Installing with brew:
brew install elm
Starting new projects is done with elm init
mkdir elm-project
cd elm-project
elm init
Built-in REPL starts by
elm repl
Local server on http://localhost:8000 starts with a command
elm reactor
To compile
elm make src/Main.elm
All of the imported modules in Main.elm are compiled automatically. Produced are html and js files. To produce only the JS file:
elm make src/Main.elm --optimize --output=elm.js
Packages are installed with
elm install elm/http
Core language
Functions are defined without commas in arguments and surrounding parenthesis. They have no return statement.
> isEven n = remainderBy 2 n == 0
> isEven 3
false
Instead of != comparing /= used. Instead of ! operator ‘not’.
Anonymous functions are defined with \ before arguments and -> before a functions code:
> isOdd = \n -> remainderBy 2 n /= 0
<function> : Int -> Bool
> isOdd 2
False : Bool
> isOdd 3
True : Bool
String are concatenated with ++
> "Good " ++ "morning"
"Good morning" : String
Prefix syntax is possible
> (++) "Good " "morning"
"Good morning" : String
All operations like length are contained within String module.
Common data structures are tuples, lists and records (maps).
Lists are defined with square brackets [] and commas
> fruits = ["apple", "banana", "oranges"]
["apple","banana","oranges"] : List String
> List.length fruits
3 : Int
Lists can contain only the same type elements.
Tuples are defined with parenthesis ()
> colors = ("red", "green", "yellow")
("red","green","yellow")
: ( String, String, String )
Tuples are allowed to contain different type elements. Tuples length is limited to three elements.
Records (maps) are defined with curly brackets {}
> user = {name = "John", city = "London", age = 30}
{ age = 30, city = "London", name = "John" }
: { age : number, city : String, name : String }
Central concept of Elm is a type system. Custom types in elm operates like enums with symbols (keywords) that start with capital letters listed with |:
type User = Anonymous | Registered | Admin
Common thing is to set an alias to a type:
type alias Colors = String
Aliases might be attached to records (maps):
type UserType = Anonymous | Registered | Admin
type alias CurrentUser = {userType: UserType, name: String}
johny = {status = Registered, name = "John"}
The above can be rewritten to a type notation:
type UserType = Anonymous String | Registered String | Admin String
johny = Registered "John"
All functions are curried automatically
> multy a b = a * b
<function> : number -> number -> number
The above actually means
<function> : number -> (number -> number)
It is possible to partly call a function
> multy a b = a * b
<function> : number -> number -> number
> multy3 = multy 3
<function> : number -> number
> multy 3 5
15 : number
Partial functions can be combined with << and >>
> multi a b = a * b
<function> : number -> number -> number
> multi2 = multi 2
<function> : number -> number
> subtract a b = a - b
<function> : number -> number -> number
> subtract5 = subtract 5
<function> : number -> number
> multiSubtract = multi2 << subtract5
<function> : number -> number
> multiSubtract 10
-10 : number
Pipes |> and <| can be applied to redirect arguments:
> 5 |> (+) 2
7 : number
> (+) 2 <| 5
7 : number
Modules are starting with exporting global scope name
module Main exposing (..)
or
module Main exposing (main)
to litereally list names to export.
One of the common construct is case associated with concrete type
type Msg = Increment | Decrement
update msg model =
case msg of
Increment ->
model + 1
Decrement ->
model - 1
Function and all the other declaration first states signatures, that implementation:
> divide: Int -> Int -> Float
| divide a b = toFloat a / toFloat b
|
<function> : Int -> Int -> Float
> divide 8 4
2 : Float
>
Analysing samples
Documentation example shows follow:
module Main exposing (..)
import Html exposing (main_)
import Browser
import Html exposing (Html, button, div, text)
import Html.Events exposing (onClick)
main =
Browser.sandbox { init = 0, update = update, view = view }
type Msg = Increment | Decrement
update msg model =
case msg of
Increment ->
model + 1
Decrement ->
model - 1
view model =
div []
[ button [ onClick Decrement ] [ text "-" ]
, div [] [ text (String.fromInt model) ]
, button [ onClick Increment ] [ text "+" ]
]
Obvious drawbacks are:
- HTML model is written in the same file as a programming code;
- Events dispatcher follows PubSub pattern (update msg model function) instead of Observer pattern.
References
- Modules are viewed at https://package.elm-lang.org/
- Overall guide https://guide.elm-lang.org/architecture/
- Programming in Elm https://elmprogramming.com/