Elm

language

style

model / view / update

subscription--(Msg)-> update --(Model)--> view
      ^                ^  ¦                ¦
      ¦                ¦  ¦                ¦
   (Model)          (Msg)(Cmd Msg)     (Html Msg)
      ¦                ¦  ¦                ¦
      ¦                ¦  v                v
===============================================
                ELM RUNTIME

Browser

https://package.elm-lang.org/packages/elm/browser/latest/Browser

main          : Program () Model Msg             -- 1st param for JS interop

-- Browser.sandbox - cannot communicate with the outside world
init          : model
view          : model -> Html msg
update        : msg -> model -> model

-- Browser.element - manages an HTML element managed by Elm
init          : flags -> (model, Cmd msg) -- !
view          : model -> Html msg
update        : msg -> model -> (model, Cmd msg) -- !
subscriptions : model -> Sub msg

-- Browser.document - body/script var app = Elm.Main.init()
-- type alias Document msg =
--   { title : String
--   , body  : List (Html msg)
--   }
init          : flags -> (model, Cmd msg)
view          : model -> Document msg
update        : msg -> model -> (model, Cmd msg)
subscriptions : model -> Sub msg

-- Browser.application - manages url changes, avoid new HTMl when url changes
-- type UrlRequest =
--   = Internal Url.Url
--   | External String
init          : flags -> Url -> Key -> (model, Cmd msg) -- Url = current url in browser
view          : model -> Document msg
update        : msg -> model -> (model, Cmd msg)
subscriptions : model -> Sub msg
onUrlRequest  : UrlRequest -> msg -- intercepts <a> clicks, msg goes to update
onUrlChange   : Url -> msg -- when the Url changes, msg goes to update

module / import

module Page.Register exposing (Msg, init, subscription)

-- on *module* exposing a type could only be either
-- - Cred(..) -- all of it
-- - Cred     -- nothing of it

import Time                          -- qualified, ONLY makes the namespace available
import Page.NotFound as NotFond      -- qualified, alias
import Article.Slug  exposing (Slug) -- open import, get Slug in scope
import Html          exposing (..)   -- open import, gets ALL on Html in scope
import SeasonMod     exposing (Season(..)) -- open import, imports all type constructors in type Season
import SeasonMod     exposing (Season)     -- qualified, imports Season

stdlib / functions

https://package.elm-lang.org/packages/elm/core/latest/

Array indexedMap toIndexedList
Basics "things imported by default"
Bitwise complement shiftLeftBy
Char toCode fromCode
Debug toString log todo
Dict merge union intersect diff
List intersperse partition unzip
Maybe andThen
Platform Program Task ProcessId Router
Platform.Cmd none
Platform.Sub batch
Process  
Result andThen mapError
Set partition
String  
Task  
Tuple mapFirst mapSecond mapBoth

https://github.com/orgs/elm/repositories?q=mirror%3Afalse+fork%3Afalse+archived%3Afalse+language%3Aelm+sort%3Aname-asc

browser 1 Browser.Navigation.{load,pushUrl}
bytes  
color  
file  
html  
http  
json  
parser  
project-metadata-utils  
random  
regex  
svg  
time Time.Posix
virtual-dom  
url  
module function  
Http    
  .get String -> Decoder a -> Request a
  .getString String -> Request String
  .send (Result Error a -> msg) -> Request a -> Cmd msg
  .CompletedLoadFeed Result Error String
  .post String -> Body -> Decoder a -> Request a
  .emptyBody Body
  .stringBody String -> String -> Body
  .request {method,header,url,body,expect,timeout,withCredentials} -> Request a
Random    
  .generate creates a generator, from the provided description
  .initialSeed creates a seed from a given integer
  .step produces newRandomValue+newSeed, from a generator+seed
  .constant generator
  .uniform generator, from a list
  .weighted generator, from a weighted list
  .map generator, take an fn maps inside the random
  .andThen generator
  .int generator
  .float generator
  .list generator helper, take an N and a generator
  .pair generator helper, takes 2 generatos
  .lazy generator, to create self-referencing generators, helps compiler
WebSocket    
  .listen String -> (String -> msg) -> Sub msg
  .send String -> String -> Cmd msg
Navigation    
  .newUrl String -> Cmd msg
  .program  
  .programWithFlags  

operators

op signature describes…
¦> a -> (a -> b) -> b the flow of data, main advantage over nested parentheses
(a -> b) -> a -> b second argument INTO the first
>> (b -> c) -> (a -> b) -> (a -> c) function compositions, indepedent of the data flow
<< (a -> b) -> (b -> c) -> (a -> c)  
++ appendable -> appendable -> appendable  

attributes/events (1st argument)

fn signature
Html.Events.on String -> Decoder msg -> Html.Attribute msg
Html.Events.onClick msg -> Attribute msg
Html.Events.onInput (String -> msg) -> Attribute msg
Html.Attributes.placeholder String -> Attribute msg
Html.Attributes.value String -> Attribute msg
Html.Attributes.class String -> Attribute msg
Browser.Events.onMouseMove Decoder msg -> Sub msg

types

  • Elm special constraint type variables, that have special constraints. Must begin with:
    • number
    • appendable (String, List)
    • comparable (Int,Float,String?…7)

Primitive

type eg fn reason fn
String "foo" MANIPULATE revert repeat replace append concat split, join, words, lines, cons, uncons, (++)
    SUBSTRING slice left right dropLeft dropRight
    CHECK length isEmpty contains startsWith indexes
    CONVERT toInt fromInt toFloat fromFloat toList fromList, fromChar
    HIGH-ORDER map filter foldl foldr any all
Char 'i' PREDICATE isUpper, isLower, isAlpha, isAlphaNum,
      toUpper, toLower, toLocaleUpper, toLocaleLower
      toCode, fromCode
Int     toFloat
Float     round, floor, ceiling, truncate
Bool     &&, ¦¦, not

Compound

create type access update match
[1,2,3] List Int     x :: xs
(1, "foo") ( Int, String ) Tuple.first   ( foo, bar )
Array.fromList Array Int Array.get Array.set  
{ name = "foo" } { name : String } rec.name { rec ¦ name = "Z" } { name }
{ "foo" }       ({ name } as person)
Just a Maybe a      
Nothing        
Ok a Result a b      
Err b        
-- even in the module where is defined, you CANNOT make one
type Never = OneMore Never
-- example type representing a Model, without field names, like in a record
type Model String Int (List Post)
  • Array, immutable
    • defining : empty fromList repeat initialize
    • get/set : get set push
    • props : length
  • Tuples max of 3 elements
  • Records
    • have a N element constructor, when defined as a type alias, the same name as the type
    • have a ".fieldname" function defined for each of the fields
    • can use extensible for function signature to receive any records with the specified field names

      point2d = { x = 1, y = 2 }
      point3d = { x = 3, y = 4, z = 5 }
      -- .x point2d => 1
      -- .x point3d => 3
      length : { a | x : Float, y : Float } -> Float
      length vector =
          sqrt (vector.x * vector.x + vector.y * vector.y)
      

elm.json

dependencies are downloaded globally at $HOME, NOT per project

source-directories ["src"]
type application
elm-version 0.19.0
dependencies  
test-dependencies  

executable

init    
install elm/browser  
make Main.elm outputs a .html
make Main.elm –output elm.js compile, point it at entrypoint file optional –optimize
repl    

codebases

snippets

-- sort by length
List.sortBy String.length ["Hi","mum","hello"]
-- sort by length and alphabetically
List.sortBy (\str -> (String.length str, str)) ["Hi","mum","hello"]

Stops browser default action (eg: fold <details>)

import Json.Decode as JD

alwaysPreventDefault : msg -> ( msg, Bool )
alwaysPreventDefault msg =
    ( msg, True )

onClickWithPreventDefault : msg -> Html.Attribute msg
onClickWithPreventDefault msg =
    preventDefaultOn "click" (JD.map alwaysPreventDefault (JD.succeed msg))

Similar to stop propagation

onClickWithStopPropagation : msg -> Html.Attribute msg
onClickWithStopPropagation msg =
    stopPropagationOn "click" (JD.map (\m -> ( m, True )) (JD.succeed msg))

Created: 2023-04-09

Updated: 2024-11-16

Back