Elm
language
- https://en.wikipedia.org/wiki/Elm_(programming_language)
- no higher kind polymorphism
- no generic map, there is List.map and Set.map
- no typeclass support
- high boilerplate code
- no higher kind polymorphism
- https://github.com/hmsk/vite-plugin-elm
- "Successors"
- (fork) https://gren-lang.org/
- each file in Elm is a module and MUST have a module statement
- to be consistent with stdlib, make the datastructure the last argument of your functions then you will be able to |> pipe freely
- comparing (==) 2 functions would throw a
runtime exception
- a "blank" html is "text """
style
- https://elm-lang.org/docs/style-guide
- https://elmprogramming.com/indentation.html
- ModuleName
- variableName
- functionName
- fieldName
- Type
- Constructor
- comments
- –
- {- -}
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 |
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)
- https://package.elm-lang.org/packages/elm/html/latest/Html-Attributes
- https://package.elm-lang.org/packages/elm/html/latest/Html-Events
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 elementsRecords
- 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 namespoint2d = { 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)
- have a N element
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
- web framework https://github.com/dillonkearns/elm-pages https://elm-pages.com/
- survey site (now closed) https://github.com/MartinSStewart/state-of-elm
- games https://github.com/rofrol/elm-games
- main site written on it https://github.com/elm/elm-lang.org/
- Example spa https://github.com/rtfeldman/elm-spa-example/
- todoapp https://github.com/evancz/elm-todomvc/blob/master/src/Main.elm
- https://elm-lang.org/examples https://github.com/dwyl/learn-elm/
- interview challenge https://github.com/scrive/elm-challenge
- fetch rss https://github.com/cmoog/nytrss/blob/master/Main.hs
- different personal tools of "some guy" https://github.com/amkhlv/usr/tree/master/share/Haskell
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))