Elm és un llenguatge de programació funcional i tipatge fort per crear interfícies d'usuari basades en navegadors web, generant estructures dinàmiques basades en JavaScript.

Elm utilitza la programació reactiva funcional i un sistema de gràfics funcional pur per construir interfícies d'usuari sense actualitzacions destructives.

Utilitza una sintaxi molt similar al Haskell però amb diferent semàntica. Elm és d'avaluació estricta (l'avaluació va de l'arrel a les branques començant per la funció main) i primerenca (en un àmbit local les instruccions s'executen per ordre d'aparició; no hi ha clàusules where).

Descripció 
La implementació d'Elm compila a JavaScript i HTML, amb ús d'estils CSS.

A Elm, la programació reactiva funcional, basada en objectes variables i relacions de dependència, relleva l'usuari de programar gestors d'esdeveniments (ang: event handlers) i rutines en mode d'inversió de control (ang:callbacks). També actualitza automàticament els objectes en pantalla.

La presentació gràfica funcional pura relleva d'actualitzar el model de document DOM.

Elm també permet incloure plantilles en llenguatge de marques Markdown.

Sintaxi i semàntica 
Elm adopta una sintaxi a l'estil del Haskell amb influències d'OCaml i F Sostingut. Per exemple l'operador "té tipus" s'escriu amb un únic caràcter ':'; els operadors d'aplicació directa (<|) i aplicació revessa (|>) són tals que (f x) és igual que (f |> x) i igual que (x |> f).

Les definicions de tipus segueixen l'esquema del Haskell. Els tipus dels paràmetres se separen amb (->) i la repetició de variables de tipus indica requeriment de coincidència.

Elm té registres extensibles que forneixen un ús segur de la flexibilitat del model d'objectes de Javascript.

El sistema de tipus suporta tipus primitius com Enters i Coma flotant, dades estructurades com ara tuples i registres, i també tipus abstractes de dades personalitzats.

La implementació de la programació reactiva funcional és moguda per esdeveniments (event-driven), volent dir que les actualitzacions són automàtiques i només en cas de necessitat. Comparteix la màxima semblança amb l'"Event-driven FRP" i l'"Arrowized FRP".

El següent programa mostra la posició del ratolí en moure'l per la pantalla.
main = lift asText Mouse.position

El valor de main es mostra en pantalla. La funció asText converteix qualsevol valor en un valor textual representable. La funció lift assegura que asText serà aplicada al senyal Mouse.position a cada canvi del valor.

Elm té un petit però expressiu conjunt de construccions de llenguatge i tractament de llistes. També té un sistema de mòduls i un model d'interfase amb funcions foranes (FFI) per al JavaScript.

Les funcions predefinides són al mòdul Prelude.

Valors 
Els valors són variables o expressions immutables. Entre els seus tipus tenim:
 Bool, number, Int, Float.
 Char, String, Text (incorpora estil)
 Time, Date.
 Element (elements estructurals)
 Form (representació gràfica), Shape, Path.
 Registres anònims extensibles (tractament funcional dels objectes de JavaScript)
 Tipus de dades algebraics (com al Haskell; facilita l'encaix de patrons).

Senyals (variabilitat) 
(Signal tipusDelValor) és el tipus de les variables o expressions que canvien de valor, amb el temps (continus) o per l'efecte d'esdeveniments (discrets).

-- obtenir el temps actual, actualitzat cada t
Time.every : Time -> Signal Time

-- obtenir la posició del ratolí
Mouse.position : Signal (Int,Int)

Els elements de formularis HTML poden variar en estil i en estat. Les funcions que els generen tornen majoritàriement un parell de senyals (senyal_de_l'element, senyal_de_l'estat) com a

-- crear una casella de marcar, amb el valor inicial indicat.
-- retorna el parell (senyal de l'estructura, senyal de l'estat)
checkbox : Bool -> (Signal Element, Signal Bool)

Senyals dependents 
Els senyals dependents són com les cel·les d'un full de càlcul que contenen una fórmula, i el seu valor es recalcula per reacció als canvis dels seus operands.

Es defineixen, o bé amb una expressió de filtre de senyals, o bé per l'aplicació d'una funció de valors, que per aplicar-la a senyals cal elevar-ne el tipus amb lift.

Per emprar un valor en un paràmetre de senyal, cal elevar-ne el tipus convertint-lo a senyal amb la funció Signal.constant.

Si la funció arrel (d'engegada), anomenada main, és un senyal, llavors s'exploraran les dependències entre senyals per obtenir-ne els independents i incloure'n els generadors en el bucle de despatx inicial.

Cada senyal manté una llista dels senyals que en depenen i que farà recalcular en cas que se li actualitzi el valor. No hi pot haver cicles en la relació de dependència.

Des de la perspectiva del llenguatge Haskell

Senyal com a instància de la classe Functor 
Vegeu signatura de la classe Functor a Haskell. De la biblioteca Signal d'Elm:

-- elevar una funció de ''valors'' a una funció de ''senyals''
lift : (a -> b) -> Signal a -> Signal b

-- (<~) és un àlies per a lift

Senyal com a instància de la classe Applicative 
Vegeu signatura de la classe Applicative a Haskell. De la biblioteca Signal d'Elm:

-- elevar un valor
constant : a -> Signal a

-- aplicació seqüencial de funció de senyals
(~) : Signal (a -> b) -> Signal a -> Signal b

-- mostreja el segon senyal seqüencialment a un canvi de valor del primer.
sampleOn : Signal a -> Signal b -> Signal b

----------------------
-- per elevar una funció de valors de N paràmetres (definides lift2 a lift8)
senyal_resultant = liftN fun_N_ària senyal1 senyal2 ... senyalN

-- equivalent amb operadors binaris en infix
senyal_resultant = fun_N_ària <~ senyal1 ~ senyal2 ~ ... ~ senyalN

Transformadors de senyals componibles. Autòmats 
És un tipus quina finalitat és possibilitar definir una seqüència de transformacions en cadena (amb possibles efectes col·laterals).

El concepte és originari del TAD Fletxa de Haskell que descriu la seqüenciació d'efectes col·laterals mitjançant l'encadenament de morfismes.

La baula d'aquest encadenament és el tipus Automaton, que designa una aplicació de valors (amb possibles efectes col·laterals) amb un paràmetre d'origen i un resultat. El tipus és polimòrfic amb dos paràmetres, el tipus de l'entrada i el de la sortida (Automaton input output).

Per encadenar-ne dues, el tipus de la sortida de l'autòmata precedent ha de coincidir amb el tipus de l'entrada del següent.

Podem generar-ne a partir d'una funció pura (que només depèn dels paràmetres) o d'una amb memòria. De la biblioteca Automaton d'Elm:
-- generador des d'una funció pura
pure : (a -> b) -> Automaton a b 

-- generadors a partir d'un estat inicial i una funció de l'entrada i de l'estat
state : b -> (a -> b -> b) -> Automaton a b 
hiddenState : s -> (a -> s -> (s,b)) -> Automaton a b 

En podem fer un transformador de senyals amb la funció Automaton.run i un valor per defecte.

run : Automaton a b -> b -> Signal a -> Signal b

-- cal aportar un resultat per defecte, per al cas de manca de senyal d'entrada
senyalResultant = run elMeuAutòmata resultatPerDefecte senyalD'entrada

Els Automatons són componibles:
-- Compon dos autòmats mitjançant l'encadenament
(>>>) : Automaton a b -> Automaton b c -> Automaton a c

...

En realitat aquests autòmats componibles són una versió particular del concepte de les Fletxes de Haskell.

Contenidors 
 List, Set, Dict.
 Maybe (paràmetres opcionals i resultats de funcions definides parcialment, com a Nothing, o bé Just v)
 Either (resultats de funcions definides parcialment amb informació de l'error, com a Right resultat o bé Left error)

Per processar una llista de senyals en un mateix paràmetre:
-- combina una llista de senyals en un senyal de la llista de valors
Signal.combine : [Signal a] -> Signal [a]

-- actualitza amb la primera que varia (cas de simultaneitat, la primera de la llista)
merges : [Signal a] -> Signal a

Eines 
 Editor i compilador en-línia: elm-lang.org/try
 Aprendre amb exemples 
 Biblioteques Elm 
 Funcions predefinides.
 Instal·lació en UNIX mitjançant l'entorn Haskell amb l'instal·lador cabal-dev

mkdir elm-compiler && cd elm-compiler
cabal-dev install elm elm-server

export PATH=$PWD/cabal-dev/bin:$PATH

Exemples de Valors (sense variabilitat)

Text estilitzat 
import Graphics.Element as Elem -- importació qualificada

unstyledText : Text
unstyledText = Text.toText "test1"

styleIt : Text -> Text
styleIt = (Text.typeface "serif"). (Text.color red) 

-- (f <| x = f x), evita l'ús de parèntesis

alignTest : Int -> Element
alignTest commonWidth = 
 let elem1 = Elem.width commonWidth <| Text.text <| styleIt unstyledText
 elem2 = Elem.width commonWidth <| Text.centered <| styleIt <| Text.toText "test2" 
 elem3 = Elem.width commonWidth <| Text.righted <| styleIt <| Text.toText "test3"

 in flow down [elem1, elem2, elem3]

main : Element
main = alignTest 200

Podeu provar-ho a l'editor online amb compilació i execució.

Polimorfisme en tipus registres 
Vegeu registres.
module MyModule where

import Color

type Named a = { a | name : String } -- registres que tinguin el camp ''name''

getName : Named a -> String
getName {name} = name

dude = {name="John Doe", age=20}
lady = {name="Jane Doe", eyesColor = Color.blue}

names : [String]
names = [ getName dude, getName lady]

fullData = [show dude, show lady]

staticElement : Element
staticElement = flow down <| map plainText
 ["Names: " ++ show names
 , show fullData
 ]
main = staticElement 
 incrustant-lo en un element div

<!DOCTYPE HTML>
<!-- MyModule.html -->
<html>
<head><meta charset="UTF-8">
 <title>MyModule</title>
 <!-- elm-runtime.js and js compiled modules -->
 <script type="text/javascript" 
 src="/your-install-directory/cabal-dev/share/Elm-N.N.N.N/elm-runtime.js"></script>
 <script type="text/javascript" src="MyModule.js"></script>
</head>
<body>
 <div id="myId" style="width:100;height:100;"></div> <!-- cal que el contenidor sigui un DIV i que estigui buit -->

 <script type="text/javascript">

Elm.embed( Elm.MyModule, document.getElementById('myId') )

</script>
 <noscript>Javascript is not enabled</noscript>
</body></html>
 compilació i prova offline
# compila a Javascript
$ elm --make -s --only-js MyModule.elm
# executa
$ browser MyModule.html

Parametritzant un programa Elm 
La clàusula port per a la interfície FFI (Foreign function interface) amb Javascript es pot aprofitar per proporcionar paràmetres a nivell de html.

module ElmMain where

port arg1 : String
port arg2 : Int
port arg3 : [String]

implode : [String] -> String
implode = concat. intersperse ", "

main = asText <| implode [arg1, show arg2, implode arg3]

<!DOCTYPE HTML>
<html>
<head><meta charset="UTF-8">
 <title>Title</title>
 <!-- elm-runtime.js i els mòduls compilats js
 (si es compila amb --make el ElmMain.js contindrà els mòduls d'usuari que s'importin -->

 <script type="text/javascript" 
 src="/your-install-directory/cabal-dev/share/Elm-N.N.N.N/elm-runtime.js"></script>
 <script type="text/javascript" src="ElmMain.js"></script>
</head>
<body>
 <div id="myId" style="width:100;height:100;"></div><!-- Elm container must be a "div" element and must be empty -->
 <script type="text/javascript">

var myPorts = {arg1: "do re mi", // de la lletra de la cançó "abc" dels "Jackson's 5"
 arg2: 123,
 arg3: ["abc", "you and me"]
 } ;

var myContainer = document.getElementById('myId'); 

Elm.embed(Elm.ElmMain, myContainer, myPorts) ;
 </script>
 <noscript>Javascript is not enabled</noscript>
</body></html>

Exemples de Senyals (amb variabilitat)

Gràfics que varien al Tictac 
Fent servir la biblioteca Graphics.Collage
myShape : Shape
myShape1 = circle 30
myShape2 = rect 60 60

myForm1 : Form
myForm1 = outlined (dashed green) myShape1
myForm2 = outlined (solid red) myShape2

formes : [Form]
formes = [myForm1 |> move (10, -10)
 , myForm2 |> move (30, -30) 
 |> rotate (degrees 45)
 |> scale 1.5

 , plainText "mytext"
 |> toForm
 |> move (20, -20)
 |> rotate (degrees 30)
 |> scale 2
 ]

mapRotate : Float -> [Form] -> [Form]
mapRotate t = let f = rotate <| degrees <| t * 10
 in map f 

f >> g = g. f 

-- senyal de temps en segons, sense decimals 
tictac : Signal Float
tictac = let f = inSeconds >> truncate >> Prelude.toFloat
 in every (2 * second) 
 |> lift f

main : Signal Element
main = constant formes
 |> lift2 mapRotate tictac
 |> lift3 collage (constant 200) (constant 200)

Comprovador de contrasenya en camp doblat, amb confirmació per canvi de color 
import Graphics.Input as Input
import Graphics.Element as Elem
import String as Str

-- comprovador amb modificador de color
passwdOkColour : String -> String -> Element -> Element
passwdOkColour passwd1 passwd2 = 
 if passwd1 == passwd2 && Str.length passwd1 >= 6 
 then Elem.color green 
 else Elem.color red

display field1Elem field2Elem submitButtonElem =
 field1Elem `above` field2Elem `above` submitButtonElem

dynamicElement : Signal Element
dynamicElement = 
 let (field1ElemSignal, fld1StateSignal) = Input.password "Type password (min. 6 characters)!"
 labeledField1Signal = let prependLabel = beside (plainText "passwd: ")
 in lift prependLabel field1ElemSignal

 (field2ElemSignal, fld2StateSignal) = Input.password "Retype password!"
 labeledField2Signal = let prependLabel = beside (plainText "control: ")
 in lift prependLabel field2ElemSignal

 (submitButton, pressedSignal) = Input.button "Submit"

 coloredButSignal = constant submitButton 
 |> lift3 passwdOkColour fld1StateSignal fld2StateSignal 

 in lift3 display labeledField1Signal labeledField2Signal coloredButSignal

main = dynamicElement

Vegeu també 
 Fletxa (programació funcional)

Referències

Enllaços externs 
 Pàgina oficial

Llenguatge de programació Haskell