Elm has a small set of language constructs, including traditional if-expressions, let-expressions for storing local values, and case-expressions for
pattern matching. As a functional language, it supports
anonymous functions, functions as arguments, and functions can return functions, the latter often by partial application of
curried functions. Functions are called by value. Its semantics include immutable values,
stateless functions, and static typing with type inference. Elm programs render HTML through a virtual DOM, and may interoperate with other code by using "JavaScript as a service".
Immutability All values in Elm are
immutable, meaning that a value cannot be modified after it is created. Elm uses
persistent data structures to implement its arrays, sets, and dictionaries in the standard library.
Static types Elm is statically typed. Type annotations are optional (due to type inference) but strongly encouraged. Annotations exist on the line above the definition (unlike C-family languages where types and names are interspersed). Elm uses a single colon to mean "has type". Types include primitives like integers and strings, and basic data structures such as lists, tuples, and records. Functions have types written with arrows, for example round : Float -> Int.
Custom types allow the programmer to create custom types to represent data in a way that matches the problem domain. Types can refer to other types, for example a List Int. Types are always capitalized; lowercase names are type variables. For example, a List a is a list of values of unknown type. It is the type of the empty list and of the argument to List.length, which is agnostic to the list's elements. There are a few special types that programmers create to interact with the Elm runtime. For example, Html Msg represents a (virtual) DOM tree whose event handlers all produce messages of type Msg. Rather than allow any value to be implicitly nullable (such as JavaScript's undefined or a
null pointer), Elm's standard library defines a Maybe a type. Code that produces or handles an optional value does so explicitly using this type, and all other code is guaranteed a value of the claimed type is actually present. Elm provides a limited number of built-in
type classes: number which includes Int and Float to facilitate the use of numeric operators such as (+) or (*), comparable which includes numbers, characters, strings, lists of comparable things, and tuples of comparable things to facilitate the use of comparison operators, and appendable which includes strings and lists to facilitate concatenation with (++). Elm does not provide a mechanism to include custom types into these type classes or create new type classes (see
Limits).
Module system Elm has a
module system that allows users to break their code into smaller parts called modules. Modules can hide implementation details such as helper functions, and group related code together. Modules serve as a namespace for imported code, such as Bitwise.and. Third party libraries (or packages) consist of one or more modules, and are available from the Elm Public Library. All libraries are versioned according to
semver, which is enforced by the compiler and other tools. That is, removing a function or changing its type can only be done in a major release.
Interoperability with HTML, CSS, and JavaScript Elm uses an abstraction called ports to communicate with
JavaScript. It allows values to flow in and out of Elm programs, making it possible to communicate between Elm and JavaScript. Elm has a library called elm/html that a programmer can use to write HTML and CSS within Elm. It uses a virtual
DOM approach to make updates efficient.
Backend Elm does not officially support server-side development. Czaplicki does consider it a primary goal, but public progress on this front has been slow. Nevertheless, there are several independent projects which attempt to explore Elm on the backend. The primary full-stack Elm platform is Lamdera, an open-core "unfork" of Elm. Czaplicki has also teased Elm Studio, a potential alternative to Lamdera, but it is not yet available to the public. Czaplicki's demos seemingly use a future version of Elm that supports type-safe
Postgres table generation. There is also speculation that that future versions of Elm would compile to
C and use
Emscripten to generate
WASM, but this is unconfirmed by Czaplicki. For full-stack frameworks, as opposed to
BaaS products, elm-pages is likely the most popular fully open-source option. It does not extend the Elm language (although it does use open-source components of the aforementioned Lamdera compiler), but rather runs the compiled
JavaScript on
Node.js. It also supports scripting using the BackendTask API. There is also Pine, an Elm to .NET compiler, which allows safe interop with C#, F#, and other
CLR languages. There were also attempts in Elm versions prior to 0.19.0 to use the
BEAM (Erlang virtual machine) to run Elm, but they are currently non-functional due to the removal of native code in 0.19.0 and changes to the package manager. One of the projects executed Elm directly on the environment, while another one compiled it to Elixir. == The Elm Architecture (TEA pattern) ==