In this article I will describe what is Elm, how to start adventure with it and some details about this language. I am still exploring this language so please forgive some mistakes.
and then to initialize first project
and initialize test to this project
In project dictionary there are created directories and files:
When project is initialized, we can create first elm application.
I use IntelliJ with Elm plug-in, however it is possible to create elm source file in notepad and save file with elm suffix.
When elm file is created, it should be compiled to JavaScript. It is done by command
By default is created a file "index.html" with JavaScript included.
All variables in Elm are immutable by design. It offers:
definition
in
function body
case variable of
case_element -> body handling case
_ -> body of default handling
if condition then
body
else
body
1. What is Elm lang?
Elm is statically typed strongly functional language compiled to JavaScript. Structure of code is similar to Python - Elm doesn't use braces but requires indentations. Strong typing protects developer from most of technical errors and unknown state of application. All technical errors are caught in compile time and developer is informed about them by detailed messages which usually contains suggestion how to fix it.2. What tools includes Elm?
Elm command support development and module upgrading. The most useful command are:- elm init - initialize project structure. creates src directory and elm.json file.
- elm repl - starts interactive programming session,
- elm reactor - runs local web server to see project
- elm make - compile code to JavaScript
- elm install - fetches packages
- elm-test init - creates tests dictionary with example sources and updates test dependence in elm.json
- elm bump - updates version of packages depending on this changing package
- elm diff - detects changes between versions of packages
- elm publish - publish your code in elm lang repository
3. How to start?
Using npm Elm tools can be installed by few commands:npm install elm
npm install elm-format
npm install elm-test
and then to initialize first project
elm init
and initialize test to this project
elm-test init
In project dictionary there are created directories and files:
- src - directory where should be stored production sources
- tests - directory with test sources
- elm.json - file with project description and dependence, ex. below
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | { "type": "application", "source-directories": [ "src", "tests" ], "elm-version": "0.19.1", "dependencies": { "direct": { "elm/browser": "1.0.2", "elm/core": "1.0.5", "elm/html": "1.0.0", "elm/http": "2.0.0", "elm/json": "1.1.3", "elm/random": "1.0.0" }, "indirect": { "elm/bytes": "1.0.8", "elm/file": "1.0.5", "elm/time": "1.0.0", "elm/url": "1.0.0", "elm/virtual-dom": "1.0.2" } }, "test-dependencies": { "direct": { "elm-explorations/test": "1.2.2" }, "indirect": {} } } |
When project is initialized, we can create first elm application.
I use IntelliJ with Elm plug-in, however it is possible to create elm source file in notepad and save file with elm suffix.
When elm file is created, it should be compiled to JavaScript. It is done by command
elm make src/Main.elm
By default is created a file "index.html" with JavaScript included.
4. Architecture
In a null shell about architecture of Elm. Elm uses pattern Model View Update. To update view is used virtual DOM tree, where each update operation creates new copy of virtual DOM tree, then each new copy is compared with previous one and then all changes are applied finally on real DOM tree in one big batch. This solution much improves changes on real DOM tree.![]() |
source: https://elmprogramming.com/virtual-dom.html |
5. Basic of language?
Types
All variables in Elm are immutable by design. It offers:
- simple types:
- Bool
- Int
- Float
- Char
- String
- complex types:
- typed List is a linked list what simplify operations on it. List can be created by collecting elements one type in square brackets
[elem, elem, elem]
or add new elements by calling
elem :: [elem]
- array is also typed as List and can be created from List. Array allows for direct access to each field
- tuple is a set of different type elements and is typed as well. tuple is created by collecting elements in round brackets
( elemA, elemB, elemC )
- record is a structure of data. Record is created by collecting name of data and values in braces
var1 = { field1 = elemA, field2 = elemB }
or
var1 = RecordType elemA elemB
where record's variables must be in the same order as in definition
type alias RecordType = { field1 : String, field2 : Int}
- Maybe is wrapper on object to avoid null pointers. It contains values: Just with value or Nothing.
- custom type - created by developer
type UserStatus = Regular | Visitor
- special types
- "_" has special meaning. It represents any type. It can be used as default value in case construction or as unused input of function
- unit type "()" - represent empty value
- inline function requires "\" before declaration
\elem -> elem + 1
- redirecting function result to the funtion on the left "<|" or right "|>" function
Let / if / case constructions
letdefinition
in
function body
case variable of
case_element -> body handling case
_ -> body of default handling
if condition then
body
else
body
Modules:
When application is bigger and bigger it is required to split code into separated files. Elm defines each separate file as module. Each module can contain private or public elements, what is defined in header of elm file.module ModuleName exposing (list_of_elements_to_be_public)for all elements instead of elements list is used two dot, ex.
module ModuleName exposing (..)Importing module can import all elements but there is required source module prefix,ex.
import Moduleor it is possible to make alias to prefix name, ex.
import Module as Mor in some cases it is better to create direct connection to element in depended module - like a static import in Java
import Module exposing (exposing_function1,exposing_function2)there is also possible to make mix of those solutions, ex.
import Module as M exposing (exposing_fun1,exposing_fun2)if there is need to move modules to subfolders, module name is preceded with folder path separated with dot (similar to Java packages), ex
module folder1.folder2.ModuleName exposing (..)To compile application it is needed only to indicate main module of application.
![]() |
source: https://elmprogramming.com/ |
Ports
Elm can be run as separated from surrounding world or can communicate with it. When Elm need to communicate with JavaScript it is required to add port specifier.1 | module MainTable exposing (..) |
When communication is from Elm to JavaScrit it is required only defining port function in Elm and callback function in JavaScript.
1 2 3 4 5 6 7 | --- ELM --- port sendData : String -> Cmd msg -- JavaScript ---- app.ports.sendData.subscribe(function(data) { alert("Data from Elm: " + data); }); |
In other way in Elm it is required to define subscriptions parameter in Browser.element, handling port function and in JavaScript code call function.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | --- ELM --- main = Browser.element { init = init , view = view , update = update , subscriptions = subscriptions } subscriptions e = receiveData changeRowValue port receiveData : (Int -> msg) -> Sub msg -- JavaScript ---- function jsEvent(idx){ app.ports.receiveData.send(idx); } |
Application Entry Point
Similar to other languages, "main" function is defined as entry point to application. If compilation is run with other output than /dev/null, error is thrown.6. Test
At the beginning it is required to install elm-testnpm install elm-testwhat modifies the file "elm.json".
Test module shares developers a few tools, what are:
- Test - test definition
- Expect - set of assertions
- Fuzz - tool to generate random data and run test for each generated value
7. Sources
[1] - Elm Guide[2] - Beginning Elm