Introduction to Elm

Evan Czaplicki

Создан для фронтенда

Компилируется в JS

Строгая типизация

Хороший DX и отсутствие ошибок в рантайме

Производительность

Синтаксис

Литералы

-- Boolean
True  : Bool
False : Bool

42    : number  -- Int or Float depending on usage
3.14  : Float

'a'   : Char
"abc" : String

-- multi-line String
"""
This is useful for holding JSON or other
content that has "quotation marks".
"""

If выражения

if powerLevel > 9000 then "OVER 9000!!!" else "meh"


if key == 40 then
    n + 1

else if key == 38 then
    n - 1

else
    n

Pattern matching

case maybe of
  Just xs -> xs
  Nothing -> []

case xs of
  hd::tl -> Just (hd,tl)
  []     -> Nothing

case n of
  0 -> 1
  1 -> 1
  _ -> fib (n-1) + fib (n-2)

Функции

Объявление

square n =
  n^2

hypotenuse a b =
  sqrt (square a + square b)

distance (a,b) (x,y) =
  hypotenuse (a-x) (b-y)


square =
  \n -> n^2

squares =
  List.map (\n -> n^2) (List.range 1 100)

Композиция

viewNames1 names =
  String.join ", " (List.sort names)

viewNames2 names =
  names
    |> List.sort
    |> String.join ", "


leftAligned (monospace (fromString "code"))
leftAligned <| monospace <| fromString "code"


fn1 = not << isEven << round << sqrt
fn2 = sqrt >> round >> isEven >> not

Типы

answer : Int
answer =
  42

factorial : Int -> Int
factorial n =
  List.product [1..n]

distance : { x : Float, y : Float } -> Float
distance {x,y} =
  sqrt (x^2 + y^2)

Структуры данных

Иммутабельность

Списки

list = [1, 2, 3, 4]
listFromRange = [1..4]
listByAppending = [1, 2] ++ [3, 4]
listByPrepending = 1 :: 2 :: 3 :: 4 :: []


list = [1,2,3,4]
-- [1,2,3,4] : List number

filteredList = List.filter (\n -> n > 2) list
-- [3,4] : List number

firstElement = List.head list
-- Just 1 : Maybe.Maybe number

restOfTheElements = List.tail list
-- Just [2,3,4] : Maybe.Maybe (List number)

Массивы

list = [1,2,3,4]
-- [1,2,3,4] : List number

filteredList = List.filter (\n -> n > 2) list
-- [3,4] : List number

firstElement = List.head list
-- Just 1 : Maybe.Maybe number

restOfTheElements = List.tail list
-- Just [2,3,4] : Maybe.Maybe (List number)

Set

import Set

set1 = Set.fromList [1,2,3,4,3,2,1]
-- Set.fromList [1,2,3,4] : Set.Set number

set2 = Set.fromList [3,4,5,6]
-- Set.fromList [3,4,5,6] : Set.Set number

intersection = Set.intersect set1 set2
-- Set.fromList [3,4] : Set.Set number

union = Set.union set1 set2
-- Set.fromList [1,2,3,4,5,6] : Set.Set number

differences = Set.diff set1 set2
-- Set.fromList [1,2] : Set.Set number

Словари

import Dict

users = Dict.fromList \
    [ ("dennis", { email = "mail@dennisreimann.de"}) \
    , ("otherdude", { email = "otherdude@example.org"}) \
    ]

usernames = Dict.keys users
-- ["dennis","otherdude"] : List String

userRecords = Dict.values users
-- [{ email = "mail@dennisreimann.de" },{ email = "otherdude@example.org" }] : List { email : String }

dennis = Dict.get "dennis" users
-- Just { email = "mail@dennisreimann.de " } : Maybe.Maybe { email : String }

Tuple

-- tuple without type definition
coordinates = (53.1201749, 8.5962037)

-- tuple with type definition
area : (Int, Int)
area = (42, 23)

-- tuple with type alias
type alias IsValid = Bool
type alias Message = String
type alias ValidationResult = (IsValid, Message)

success : ValidationResult
success = (True, "All is good.")

error : ValidationResult
error = (False, "Something went wrong.")

Records

-- record without type definition
coordinate =
    { latitude = 53.1201749
    , longitude = 8.5962037
    }


-- record with type definition
area : { width : Int, height : Int }
area =
    { width = 42
    , height = 23
    }


-- record with type definition via type alias
type alias User =
    { login : String
    , isAdmin : Bool
    }


alice : User
alice =
    { login = "alice"
    , isAdmin = False
    }


bob : User
bob =
    { login = "bob"
    , isAdmin = True
    }

Нет undefined / null

Maybe

> type Maybe a = Nothing | Just a

> Nothing
Nothing : Maybe a

> Just
<function> : a -> Maybe a

> Just "hello"
Just "hello" : Maybe String

> Just 1.618
Just 1.618 : Maybe Float

getTeenAge : User -> Maybe Int
getTeenAge user =
  case user.age of
    Nothing ->
      Nothing

    Just age ->
      if 13 <= age && age <= 18 then
        Just age

      else
        Nothing

Интересные идеи

Сообщения об ошибках

Package system

Forced semver

Applications

Model-View-Update

import Html exposing (..)


-- MODEL

type alias Model = { ... }


-- UPDATE

type Msg = Reset | ...

update : Msg -> Model -> Model
update msg model =
  case msg of
    Reset -> ...
    ...


-- VIEW

view : Model -> Html Msg
view model =
  ...

Usage in production

Как внедрить

  • Have an advocate
  • Start small
  • Fix a problem
  • Write Elm code

Минусы

  • Экспериментальный
  • Нет четкого плана развития
  • Opinionated
  • Проект одного человека

Вопросы?

Made with Slides.com