elm-logo.png

Introduction to Elm

Elm bills itself as a “delightful language for reliable webapps”. That’s a pretty accurate claim.

Getting Started

Go right to the Examples Page and work through each of the examples, one by one. They actually have useful comments.

Then go visit the Docs Page and visit most of the articles (in order). The important ones are the Quick Start for JavaScript Programmers, the Syntax Reference. Browse the entire Elm Language Guide.

Also of interest is the cool Elm Cheat Sheet.

Now, here’s one version of Hello, World:

hello.elm
import Html exposing (text)

main =
    text "Hello World"

You can run this in the Try Elm playground. (There are other playgrounds out there, too, including Ellie and runelm.io.) To make your own app on your own machine, store the program in the file hello.elm and use the command line:

$ elm make hello.elm

If you’re running Elm for the first time in this directory, Elm will realize you haven’t set anything up, so it will ask you for permission to install three packages (elm-lang/core, elm-lang/html, and elm-lang/virtual-dom). The installation will write information about the packages into the file elm-package.json and will download the packages themselves from a global repository and place them in the folder elm-stuff.

After the packages are installed, the elm make command continues by producing the output file index.html. Go ahead and run this however you normally “run” (or view) HTML pages (e.g., open index.html on macOS, or start index.html on Windows, or just drag it into a browser).

Here’s another example:

fib.elm
import Html exposing (Html, ul, li, text)
import List exposing (reverse, map, repeat)

fibsUpTo : Int -> List Int
fibsUpTo n =
    let accumulate fibs =
        case fibs of
            x :: y :: rest -> if x + y > n then fibs else accumulate (x+y::fibs)
            _ -> []
    in
        reverse (accumulate [1, 0])

main : Html Never
main =
    fibsUpTo 100000 |> map (toString >> text >> repeat 1 >> li []) |> ul []

You can run this in an online Elm runner, or on your local machine. Here’s an easy way to build and run in one step locally (on macOS):

$ elm make fib.elm && open index.html

Do you see what’s going on? The Elm expression

ul []
  [ li [] [text 0]
  , li [] [text 1]
  , li [] [text 1]
  , li [] [text 2]
  , ...
  , li [] [text 75025]
  ]

evaluates to the HTML:

<ul><li>0</li><li>1</li><li>1</li><li>2</li>...<li>75025</li></ul>

So ul is a function which takes a list of HTML attributes (yes it was empty in this example), and a list of (child) HTML elements, and produces an HTML unordered list element.

You may have been wondering....

Are those type annotations necessary?
No, Elm can figure out types for you. But the annotations add some nice documentation, and most Elm programmers use them.

What is the type Html Never that main has?
It is the type of HTML elements that generate messages of type Never.

Why are Elm type annotations on a separate line, and not interleaved into the function definition?
It’s so they are unobtrusive. And so you can add them later to code that doesn’t have them, with less chance of messing things up.

How about some graphics? Just like Elm has functions for HTML elements and attributes, it has functions for the elements and attribites of SVG also. Here’s a little app that makes a pretty picture:

colored_circles.elm
import Html exposing (Html)
import Svg exposing (..)
import Svg.Attributes exposing (..)

main : Html Never
main =
    svg
        [ width "300", height "300", viewBox "-150 -150 300 300" ]
        (List.map shape (List.range 0 23))

shape : Int -> Svg Never
shape n =
    let
        angle = 15 * toFloat n |> degrees
    in
        circle
            [ cx (100 * cos angle |> toString)
            , cy (100 * sin angle |> toString)
            , r "15"
            , fill <| "hsl(" ++ (15 * n |> toString) ++ ", 90%, 60%)"
            ] []

If you try to compile this with elm make colored_circles.elm now, you’ll get an error because Elm cannot find the Svg module by default. That module exists in the package elm-lang/svg. So first enter:

$ elm package install elm-lang/svg

Now you can compile and open (on a Mac) with:

$ elm make colored_circles.elm && open index.html

elm-colored-circles.png

Pssst, this code works in an online editor, too.

Types

We’ll begin our techincal introduction to Elm with its type system. Elm is statically typed. This means you can tell the type of every expression in your program without ever running it.

The Basic Types

The five simple types are Bool, Int, Float, Char, and String. Type names start with an uppercase letter.

$ elm repl
> 7.5 * 3.88
29.099999999999998 : Float
> False && True
False : Bool
> 7 / 2
3.5 : Float
> 7 // 2
3 : Int
> 7 % 2
1 : Int
> 'π'
'π' : Char
> "Привет мир"
"Привет мир" : String
> String.length("Привет мир")
10 : Int

Elm has lists. Good to know: List String and List Float are different types.

> ["spot", "spike"]
["spot","spike"] : List String
> [1.5, 2.2, sqrt(110)]
[1.5,2.2,10.488088481701515] : List Float
> [[], ['c'], ['c','a','t']]
[[],['c'],['c','a','t']] : List (List Char)
> 'd' :: ['o', 'g']
['d','o','g'] : List Char
> False :: True :: False :: []
[False,True,False] : List Bool

Elm’s product types are called tuples:

> (10//2, "dog", False)
(5,"dog",False) : ( Int, String, Bool )
> ('$', 'π')
('$','π') : ( Char, Char )
> ()
() : ()

That last type is the type of zero-element tuples. You can make tagged prodcuts, called records:

> p = {x=5.0, y=3.2, color="red"}
{ x = 5, y = 3.2, color = "red" } : { color : String, x : Float, y : Float }
> p.x
5 : Float
> .x p
5 : Float
> {p | color="green"}
{ x = 5, y = 3.2, color = "green" } : { x : Float, y : Float, color : String }

Elm handles sum types through its custom types. Use pattern matching to get at the variants:

> type Shape = Circle Float | Rectangle Float Float
> area s =\
|   case s of\
|     Circle r -> pi * r * r\
|     Rectangle w h -> w * h
 : Repl.Shape -> Float
>
> area (Circle 10) 
314.1592653589793 : Float
> area (Rectangle 7 6)   
42 : Float
Those backslashes are not part of Elm. I just had to type them because that is the way you tell the REPL that your entry continues on the next line. And those vertical bar symbols are the prompt you get when you are continuing an entry across multiple lines.

This type declaration created a new type called Shape, a function Circle that takes in a float and produces a shape, and a function Rectangle that (essentially) takes in two floats and produces a shape. You can call Circle and Rectangle constructors if you like, but don’t call them types.

Functions are values so they have types too:

> \n -> n // 2
<function> : Int -> Int
> \(x, y) -> 2 * x % y
<function> : ( Int, Int ) -> Int
> \a -> \b -> "hello" :: b :: a
<function> : List String -> String -> List String

> Circle
<function> : Float -> Repl.Shape
> Rectangle
<function> : Float -> Float -> Repl.Shape

Type Variables

You can infer that the type of \x -> [x*pi, 2*x*pi] is Float -> List Float.

But what is the type of \x -> [x]? Interesting question. Certainly, the type of the result of calling this function is pretty obvious:

> (\x -> [x]) "dog"
["dog"] : List String
> (\x -> [x]) False
[False] : List Bool

So it looks like the argument of the function can be of any type, and the result is a list of whatever the argument type is. Is that so?

> \x -> [x]
<function> : a -> List a

Yep it is. And as you might have guessed, type variables start with a lower case letter. Here are some more examples:

> \x -> (x, x)
<function> : a -> ( a, a )
> \x -> \y -> (x, (y, x), y)
<function> : a -> b -> ( a, ( b, a ), b )
> \x -> \y -> \(z, w) -> y / 3
<function> : a -> Float -> ( b, c ) -> Float
> type Tree a = Leaf a | Node (Tree a) (Tree a)
> Node (Leaf 3) (Node (Leaf 5) (Leaf 8))
Node (Leaf 3) (Node (Leaf 5) (Leaf 8)) : Tree number
> []
[] : List a

That tree datatype was pretty cool, wasn’t it? It is really common to see type variables in custom types. In fact, one of the most common such types in Elm is the Maybe type, which Elm uses because it doesn’t have exceptions or null references:

type Maybe a = Just a | Nothing

Maybes are used a lot:

> import List exposing(head, tail, minimum, maximum)
> head [1,2,3] == Just 1
True : Bool
> head [] == Nothing
True : Bool
> tail [1,2,3] == Just [2,3]
True : Bool
> tail [] == Nothing
True : Bool
> List.maximum [6, -9, 4, 20, -1] == Just 20
True : Bool
> List.maximum [] == Nothing
True : Bool
> maximum [6, -9, 4, 20, -1] == Just 20
True : Bool
> maximum [] == Nothing
True : Bool

Special Type Variables

Generally, a type variable can be instantiated with (or unified with) any concrete type whatsoever. That is, a function that takes a List a as its parameter can be called with a List Float argument. No problem. But sometimes not just any type will do:

So how to we infer these types? if we have to give a type to \x -> \y -> x ++ y we CANNOT say:

Elm’s answer is to introduce special type variables:

If you are coming to Elm from Haskell-land, you might think that number, comparable, and appendable are type classes. Well they are not. They are simply type variables that the compiler has intimate knowledge of and are treated very special. They are a far weaker concept than type classes. Elm does not have type classes. You cannot create your own special type variables.

Also, you might run into the type variable compappend which either is or is not one of these special variables: even the official Elm FAQ seems conflicted on this question. Sigh.
Exercise: What type does Elm infer for \(x, y) -> (x+1, y+1)? (Use the REPL)

Modules

At the language level, Elm programs are made up of modules. Each module can export only certain things and import certain things. If you don’t start your file with a module declaration, a module named Main is assumed. Learn by example. Here is a module that contains three values (all functions) but exports only one of them:

Anagrams.elm
module Anagrams exposing (anagrams)

import String exposing (toList, fromList)
import List exposing (concatMap, map, foldr)

insertEverywhere : a -> List a -> List (List a)
insertEverywhere x xs =
    case xs of
        [] -> [[x]]
        (y::ys) -> (x::y::ys) :: map ((::)y) (insertEverywhere x ys)

permutations : List a -> List (List a)
permutations =
    foldr (concatMap << insertEverywhere) [[]]

anagrams : String -> List String
anagrams s =
    s |> toList |> permutations |> map fromList

And here is an app that uses the module:

anagramapp.elm
import Anagrams exposing (anagrams)
import Html exposing (Html, pre, text)

main =
    pre [] [anagrams "aeginrst" |> String.join "\n" |> text]

WHat do you have to explicitly import? Good question. There are a few imports that are implicitly done for you at the top of every Elm file. These imports as of Elm 0.18 are:

import Basics exposing (..)
import List exposing ( List, (::) )
import Maybe exposing ( Maybe( Just, Nothing ) )
import Result exposing ( Result( Ok, Err ) )
import String
import Tuple
import Debug
import Platform exposing ( Program )
import Platform.Cmd exposing ( Cmd, (!) )
import Platform.Sub exposing ( Sub )

In addition to the modules you write yourself, there are hundreds and hundreds of standard modules and community-contributed modules stored in a global package repository. (Just FYI, the modules in the default import list, come from a very important package called elm-lang/core.) You grab these modules via the Elm package manager, which we’ll cover pretty soon. But first, more about Elm itself.

Operators

Elm predefines the following infix operators:

OperatorsPrecAssocDescription
<<9Rcomposition: (f << g)x == f(g(x))
>>9Lcomposition: (f >> g)x == g(f(x))
^8Rexponentiation
* / // % rem7Lmultiply, divide, integer divide, modulo, remainder
+ -6Ladd, subtract
:: ++5Lcons, append
< <= > >= == /=4Noneless, less or equal, greater, greater or equal, equal, not equal
&&3Rshort-circuit logical and
||2Rshort-circuit logical or
<|0Rapplication: f <| x == f(x)
|>0Lapplication: f |> x == f(x)

To use an infix operator in the prefix position, enclose it in parentheses:

> (*) 3 7
21 : number
> times3 = (*) 3
<function> : number -> number
> times3 50
150 : number

You can create your own infix operators, too. Set the precedence and associativity with the infixl (left associative), infixr (right associative) or infix (non-associative) functions. Example:

customop.elm
import Html exposing (div, text)

(<-*->) x y = 2 * x + y
infixr 7 <-*->

main =
  div [] [text <| toString <| 8 <-*-> 2 ^ 3 <-*-> 5 + 2]

The above script produces the value 39. We made the new operator right associative and placed its precedence lower than expoentation but higher than addition. The evaluation proceeds like so:

    8 <-*-> 2 ^ 3 <-*-> 5 + 2
    =  8 <-*-> 8 <-*-> 5 + 2
    =  8 <-*-> 21 + 2
    =  37 + 2
    =  39

Let

Elm’s let-expression lets you bind local variables to compose a more complex expression. Example:

let
    x =
        3 * 8
    y =
        4 ^ 2
in
    2 * x + y

It’s pretty much shorthand for:

(\x -> \y -> 2 * x + y)(3 * 8)(4 ^ 2)

Functional Programming

Elm wants to be a pure functional language. This means: Every function should return the same value for the same arguments no matter when it is called. So there shouldn't be any global state. There should be no side effects, no mutable variables, no assignments, no loops.

Hold on! Why would we ever care about this? Well, it turns out that pure functions have lots of advantages:
  • They are easier to reason about and prove correct
  • They are easier to to compose
  • They are easier to to test
  • They are easier to to debug
  • They are easier to to parallelize

Okay, now that we know pure functions are good, how do we program in such a way? You might have to change your thinking:

AvoidAlternative
While loopsTail recursion
For loops through sequencesMap, filter, reduce, or other functions on lists
For loops over numbersFunctions on ranges, or tail recursion
Adding elements to a data structureReturn a new data structure, just like the old one, except with a new element
Modifying a data structureReturn a new data structure, just like the old one, except with the modification made
Modifying the DOMThe DOM is just a data structure, so see above, and use a Virtual DOM that backs the real DOM
Throwing exceptions or setting global error codesChain maybes and results
Asking for a random number, the current time, or the current position of the mouseDon’t ask for these things! We cannot make pure functions that return these! But the callbacks for these things can be pure

We’ll look at the basics first. Then we’ll get into the interactive “effects” after that.

Replacing Loops with Recursion

Here’s a typical solution using a while loop that determines how many years you need to grow $1000 into $2000 at a 3.5% annual interest rate:

years = 0
amount = 1000
while amount < 2000:
    amount = amount * 1.035;
    years = years + 1
return years

Elm doesn’t have assignable, mutable variables, so we have to create a function that takes us from one (years, amount) pair to the next one. Here’s the progression we need to capture in a function:

yearsNeeded(0, 1000)
    = yearsNeeded(1, 1035.0)
    = yearsNeeded(2, 1071.225)
    = yearsNeeded(3, 1108.7178749999998)
    = yearsNeeded(4, 1147.5230006249997)
    = yearsNeeded(5, 1187.6863056468746)
    = yearsNeeded(6, 1229.2553263445152)
    = yearsNeeded(7, 1272.279262766573)
    = yearsNeeded(8, 1316.809036963403)
    = yearsNeeded(9, 1362.897353257122)
    = yearsNeeded(10, 1410.598760621121)
    = yearsNeeded(11, 1459.9697172428603)
    = yearsNeeded(12, 1511.0686573463602)
    = yearsNeeded(13, 1563.9560603534826)
    = yearsNeeded(14, 1618.6945224658543)
    = yearsNeeded(15, 1675.348830752159)
    = yearsNeeded(16, 1733.9860398284845)
    = yearsNeeded(17, 1794.6755512224813)
    = yearsNeeded(18, 1857.489195515268)
    = yearsNeeded(19, 1922.5013173583022)
    = yearsNeeded(20, 1989.7888634658427)
    = yearsNeeded(21, 2059.431473687147)
    = 21

We want a function (years, amount) and make a recursive call with (years + 1, amount * 1.035). But if amount is already over 2000, we have our answer and return years.

-- Here's the function
yearsNeeded years amount =
  if amount > 2000 then years else yearsNeeded (years + 1) (amount * 1.035)

-- Call it to solve our initial problem
yearsNeeded 0 1000

Another example. How many steps are there in the Collatz Sequence for a given number?

def collatz(n):
    count = 0
    while n > 1:
        n = even(n) ? n / 2 : 3 * n + 1
        count = count + 1
    return count

Our first inclination might be to simply write

-- Inefficient
collatz n =
    if n == 1 then 0 else collatz(if n % 2 == 0 then n // 2 else 3 * n + 1) + 1

but this is inefficient because it is not tail-recursive. Instead, let’s use the technique from the previous example:

collatz n =
    let
        c count n =
            if n == 1 then count
            else c (count+1) (if n % 2 == 0 then n // 2 else 3 * n + 1)
    in
        c 0 n
Exercise: Show that in addition to replacing while-loops, you also replace for-loops with this technique. First give a program in C that runs through all the integers in the range 0 to 300 (inclusive) and sums up those and only those values evenly divisible by 3 or 7. Then, write the same program in Elm, using tail recursion.

Recursing on Lists

Most for-loops over lists iterate over each list item or each list index (or both).

Map, Filter, and Fold

TODO

Chaining updates

TODO

The Elm Architecture

So how do we do functional programming on the web? Surely interaction requires state? Right?

Here’s how Elm does it. Up to now, we’ve only seen examples where main has the type Html.Html a. But it can also have the type Platform.Program a b c. The easiest ways to make objects of type Program a b c are with the functions Html.beginnerProgram and Html.program. Here’s a “beginner program” the computes a BMI from two text fields, as you type:

bmi.elm
import Html exposing (Html, body, input, text, h1, p)
import Html.Attributes exposing (style, value)
import Html.Events exposing (onInput)

type alias Model = { weight: String, height: String }
type Msg = ChangeWeight String | ChangeHeight String

bmi pounds inches =
    let
        kilosPerPound = 0.453592
        metersPerInch = 0.0254
        kilos = pounds * kilosPerPound
        meters = inches * metersPerInch
    in
        kilos / (meters * meters)

bmiMessage weightString heightString =
    case (String.toFloat weightString, String.toFloat heightString) of
        (Ok w, Ok h) -> "The BMI is " ++ toString (bmi w h)
        (Err s, _) -> s
        (_, Err s) -> s

main =
    Html.beginnerProgram { model = model, view = view, update = update }

model : Model
model = { weight = "0", height = "0"}

update : Msg -> Model -> Model
update msg model =
    case msg of
        ChangeWeight w -> { model | weight = w }
        ChangeHeight h -> { model | height = h }

view : Model -> Html Msg
view model =
    body [style [("textAlign", "center")]]
        [ h1 [] [text "Find Your BMI"]
        , p [] [text "Weight in pounds ", input [onInput ChangeWeight, value model.weight] []]
        , p [] [text "Height in inches ", input [onInput ChangeHeight, value model.height] []]
        , p [] [text <| bmiMessage model.weight model.height]
        ]

The beginnerProgram function creates a program out of three parts:

All the functions in the code are pure. They just get called at times you can’t predict.

Exercise: You’ll eventually want to move from beginnerProgram to program. Read about subscriptions in the Elm Tutorial and the Elm Guide.

Packages

Elm programs are made up of modules. Where can you find modules? Thousands of these have been bundled up into pacakges which you can install with the Elm package manager. There are many hundreds of packages out there. Here are few of them:

PackageModules
elm-lang/core Array Basics Bitwise Char Color Date Debug Dict Json.Decode Json.Encode List Maybe Platform Platform.Cmd Platform.Sub Process Random Regex Result Set String Task Time Tuple
elm-lang/virtual-dom VirtualDom
elm-lang/html Html Html.Attributes Html.Events Html.Keyed Html.Lazy
elm-lang/svg Svg Svg.Attributes Svg.Events Svg.Keyed Svg.Lazy
elm-lang/http Http Http.Progress
elm-lang/websocket WebSocket WebSocket.LowLevel
elm-community/basics-extra Basics.Extra
elm-community/webgl WebGL WebGL.Settings WebGL.Settings.Blend WebGL.Settings.DepthTest WebGL.Settings.StencilTest WebGL.Texture
elm-community/elm-test Expect Fuzz Test Test.Runner
elm-community/linear-algebra Math.Matrix4 Math.Vector2 Math.Vector3 Math.Vector4
mgold/elm-date-format Date.Format Date.Local Time.Format

Make sure to browse the entire package repository.

Popular Modules

Finally, just for fun, here are partial contents of some of the more popular modules:

Basics

(==): a -> a -> Bool                         -- equality, may give runtime error
(/=): a -> a -> Bool                         -- inequality, may give runtime error
(<): comparable -> comparable -> Bool
(>): comparable -> comparable -> Bool
(<=): comparable -> comparable -> Bool
(>=): comparable -> comparable -> Bool
(<): comparable -> comparable -> Bool
max: comparable -> comparable -> Bool
min: comparable -> comparable -> Bool
type Order = LT | EQ | GT
compare: comparable -> comparable -> Order
not: Bool -> Bool -> Bool
(&&): Bool -> Bool -> Bool                   -- logical and (short circuit)
(||): Bool -> Bool -> Bool                   -- logical or (short circuit)
xor: Bool -> Bool -> Bool
(+): number -> number -> number
(-): number -> number -> number
(*): number -> number -> number
(/): Float -> Float -> Float                 -- division (promotes Int args to Float)
(^): number -> number -> number              -- exponentiation
(//): Int -> Int -> Int                      -- integer division
(rem): Int -> Int -> Int                     -- remainder
(%): Int -> Int -> Int                       -- modulo
negate: number -> number
abs: number -> number
sqrt: Float -> Float
clamp: number -> number -> number -> number  -- low hi value
logBase : Float -> Float -> Float            -- base value
e : Float
pi : Float
cos : Float -> Float
sin : Float -> Float
tan : Float -> Float
acos : Float -> Float
asin : Float -> Float
atan : Float -> Float                         -- don't use this
atan2 : Float -> Float -> Float               -- y x
round : Float -> Int
floor : Float -> Int
ceiling : Float -> Int
truncate : Float -> Int                       -- round toward zero
toFloat : Int -> Float
degrees : Float -> Float
radians : Float -> Float
turns : Float -> Float
toPolar : (Float, Float) -> (Float, Float)
fromPolar : (Float, Float) -> (Float, Float)
isNaN : Float -> Bool
isInfinite : Float -> Bool
toString : a -> String
(++) : appendable -> appendable -> appendable
identity : a -> a
always : a -> b -> a
(<|) : (a -> b) -> a -> b
(|>) : a -> (a -> b) -> b
(<<) : (b -> c) -> (a -> b) -> a -> c
(>>) : (a -> b) -> (b -> c) -> a -> c
flip : (a -> b -> c) -> b -> a -> c
curry : ((a, b) -> c) -> a -> b -> c
uncurry : (a -> b -> c) -> (a, b) -> c
type Never                                    -- the type with no values
never : Never -> a

String

Strings are enclosed in double quotes and are not lists of characters.

isEmpty: String -> Bool
length: String -> Int
reverse: String -> String
repeat: Int -> String -> String
cons: Char -> String -> String
uncons: String -> Maybe (Char, String)
fromChar: Char -> String
append: String -> String -> String
concat: List String -> String
split: String -> String -> List String      -- sep, stringToSplit
join: String -> List String -> String       -- sep, stringToJoin
words: String -> List String
lines: String -> List String
slice: Int -> Int -> String -> String       -- start, end, stringToSlice
left: Int -> String -> String
right: Int -> String -> String
dropLeft: Int -> String -> String
dropRight: Int -> String -> String
contains: String -> String -> Bool
startsWith: String -> String -> Bool        -- sub, largerString
endsWith: String -> String -> Bool          -- sub, largerString
indexes: String -> String -> List Int
indices: String -> String -> List Int
toInt: String -> Result String Int
toFloat: String -> Result String Float
toList: String -> List Char
fromList: List Char -> String
toUpper: String -> String
toLower: String -> String
pad: Int -> Char -> String -> String        -- len, padChar, stringToPad
padLeft: Int -> Char -> String -> String    -- len, padChar, stringToPad
padRight: Int -> Char -> String -> String   -- len, padChar, stringToPad
trim: String -> String
trimLeft: String -> String
trimRight: String -> String
map: (Char -> Char) -> String -> String
filter: (Char -> Bool) -> String -> String
foldl: (Char -> b -> b) -> b -> String -> b
foldr: (Char -> b -> b) -> b -> String -> b
any: (Char -> Bool) -> String -> Bool
all: (Char -> Bool) -> String -> Bool

List

isEmpty : List a -> Bool
length : List a -> Int
reverse : List a -> List a
member : a -> List a -> Bool
head : List a -> Maybe a
tail : List a -> Maybe (List a)
filter : (a -> Bool) -> List a -> List a
take : Int -> List a -> List a
drop : Int -> List a -> List a
singleton : a -> List a
repeat : Int -> a -> List a
range : Int -> Int -> List Int
(::) : a -> List a -> List a
append : List a -> List a -> List a
concat : List (List a) -> List a
intersperse : a -> List a -> List a
partition : (a -> Bool) -> List a -> (List a, List a)
unzip : List (a, b) -> (List a, List b)
map : (a -> b) -> List a -> List b
map2 : (a -> b -> result) -> List a -> List b -> List result
map3 : (a -> b -> c -> result) -> List a -> List b -> List c -> List result
map4 : (a -> b -> c -> d -> result) -> List a -> List b -> List c -> List d -> List result
map5 : (a -> b -> c -> d -> e -> result) -> List a -> List b -> List c -> List d -> List e -> List result
filterMap : (a -> Maybe b) -> List a -> List b
concatMap : (a -> List b) -> List a -> List b
indexedMap : (Int -> a -> b) -> List a -> List b
foldr : (a -> b -> b) -> b -> List a -> b
foldl : (a -> b -> b) -> b -> List a -> b
sum : List number -> number
product : List number -> number
maximum : List comparable -> Maybe comparable
minimum : List comparable -> Maybe comparable
all : (a -> Bool) -> List a -> Bool
any : (a -> Bool) -> List a -> Bool
scanl : (a -> b -> b) -> b -> List a -> List b
sort : List comparable -> List comparable
sortBy : (a -> comparable) -> List a -> List a
sortWith : (a -> a -> Order) -> List a -> List a

Maybe

type Maybe a = Just a | Nothing
withDefault : a -> Maybe a -> a
map : (a -> b) -> Maybe a -> Maybe b
map2 : (a -> b -> value) -> Maybe a -> Maybe b -> Maybe value
map3 : (a -> b -> c -> value) -> Maybe a -> Maybe b -> Maybe c -> Maybe value
map4 : (a -> b -> c -> d -> value) -> Maybe a -> Maybe b -> Maybe c -> Maybe d -> Maybe value
map5 : (a -> b -> c -> d -> e -> value) -> Maybe a -> Maybe b -> Maybe c -> Maybe d -> Maybe e -> Maybe value
andThen : (a -> Maybe b) -> Maybe a -> Maybe b

Result

type Result error value = Ok value | Err error
map : (a -> value) -> Result x a -> Result x value
map2 : (a -> b -> value) -> Result x a -> Result x b -> Result x value
map3 : (a -> b -> c -> value) -> Result x a -> Result x b -> Result x c -> Result x value
map4 : (a -> b -> c -> d -> value) -> Result x a -> Result x b -> Result x c -> Result x d -> Result x value
map5 : (a -> b -> c -> d -> e -> value) -> Result x a -> Result x b -> Result x c -> Result x d -> Result x e -> Result x value
andThen : (a -> Result x b) -> Result x a -> Result x b
withDefault : a -> Result x a -> a
toMaybe : Result x a -> Maybe a
fromMaybe : x -> Maybe a -> Result x a
mapError : (x -> y) -> Result x a -> Result y a