+ All Categories
Home > Technology > What is Elm and Why Should I care?

What is Elm and Why Should I care?

Date post: 07-Jan-2017
Category:
Upload: thomas-groshong
View: 1,137 times
Download: 0 times
Share this document with a friend
30
WHAT IS ELM AND WHY SHOULD I CARE? twitter & github: @tgroshon http://tgroshon.github.io/elm-pandamonium-pres
Transcript

WHATISELMANDWHY

SHOULDICARE?twitter&github:@tgroshon

http://tgroshon.github.io/elm-pandamonium-pres

DIRECTCOMPLAINTS

ASFOLLOWS

GOALS

1. ApplyElm'sgoodideastoourdailywork

2. PromoteElmasadevelopmenttool

AGENDA

1. IntroductiontoElm

2. DetailsofHowitWorks

1. TypeAnalysisAdvantages

2. Signals->ValuesoverTime

3. AbstractingAwaySide-Effects

3. Sum-up

FORMAT

SomepersuasionfollowedbyanImmediateAction(IA)

INTRO:SYNTAXHaskell-likesyntax

StaticallyTyped

Declarative

Compile-to-JavaScript

import Graphics.Element exposing (..)import Window

main : Signal Elementmain = Signal.map resizeablePaint Window.dimensions

resizeablePaint : (Int,Int) -> ElementresizeablePaint (w,h) = fittedImage w h "/imgs/paint.jpg"

-- Types can be ommitted/inferred in most cases but are nice for Doc

INTRO:TOOL-CHAINWritteninHaskell

elm-make # Compiles Elm to JSelm-package # Package Managerelm-repl # A Read-Eval-Print-Loopelm-reactor # Quick-start Watcher/Builderelm # Wrapper around all the tools

OTHERTOOLS

WebpackLoader:

elm-makeJSBindings:

https://github.com/rtfeldman/elm-

webpack-loader

https://github.com/rtfeldman/node-elm-compiler

THETYPEANALYSIS

ADVANTAGETHISJUSTIN:DYNAMICTYPESAREOUT,

STATICTYPESAREIN!

AdvantagesofElm'sTypeSystem

CatchSimpleErrors

BanishNulls

EnforceSemanticVersioning

IA:Flow

THESIMPLEERRORSGoodbyespellingmistakesandrefactoringlapses:

BANISHNULLIcallitmybillion-dollarmistake.Itwasthe

inventionofthenullreferencein1965.-

TonyHoare(BuilderofAlgolW)

NonullsinElm,JustMaybes:

type Maybe a = Just a | Nothing

Allowsthecompilertoenforce"null-checks"whenneeded.

ENFORCINGSEMANTIC

VERSIONINGelm-packagewillbumpversionsforyou,automatically

enforcingtheserules:

PATCH-theAPIisthesame,noriskofbreakingcode

MINOR-valueshavebeenadded,existingvaluesare

unchanged

MAJOR-existingvalueshavebeenchangedorremoved

EvenRust-langistalkingaboutaddingsimilarchecks:

https://users.rust-lang.org/t/signature-based-api-

comparison/2377

IA:FLOWflowtype.org

/* @flow */function foo(x) { return x * 10;}foo('Hello, world!'); // Error: This type is incompatible with ...: string

/* @flow */function foo(x: string, y: number): string { return x.length * y;}foo('Hello', 42); // Error: number ... type is incompatible with ... string

Babelwillstripitoutforyou:

http://babeljs.io/docs/plugins/transform-flow-strip-types/

ONEBEEFWITHFLOWInJavaScript,nullimplicitlyconvertstoall

theprimitivetypes;itisalsoavalid

inhabitantofanyobjecttype.

Incontrast,Flowconsidersnulltobea

distinctvaluethatisnotpartofanyother

type.

Let'sbeHonest:InJavaScript,alltypesarenullable!

Requiresprogrammerdisciplinetobehonestaboutwhich

varsarenotMaybe(fewerthanwethink)

Notagreatdecisionforagradually-typedsystemovera

languagewithnullabletypes

RECOMMENDATION

Asahabitinflow,markthingsasMaybe

SIGNALS->VALUES

OVERTIMEDiscretevaluesovertime

SignalGraphs

IA:RxJS,Most.js,Flyd

DISCRETEVALUES

OVERTIMEtype Signal a

Avaluethatchangesovertime.Every

signalisupdatedatdiscretemomentsin

responsetoeventsintheworld.

SolikeanEventEmitter?Almost,andnotquite.

TheReactiveinElmFunctional-ReactiveProgramming

SIGNAL

CHARACTERISTICSSynchronous:FIFO

Infinite&Static:Youcannotdelete,create,orunsubscribe

fromsignalsatruntime.

SIGNALGRAPHYourprogramendsupbeingagraphofsignals.

Thinkofpipes(streams):(a)sources,(b)branches,and(c)

sinks.

SIGNALGRAPH

(CONT'D)AnApplication'ssignalgraphcanhavemultiplesources,

branches,andsinks.

Sources:

position : Signal (Int, Int) -- Mouseclicks : Signal () --

dimensions : Signal (Int, Int) -- Window

Branches(Transforms):

map : (a -> b) -> Signal a -> Signal bfilter : (a -> Bool) -> a -> Signal a -> Signal amerge : Signal a -> Signal a -> Signal afoldp : (a -> s -> s) -> s -> Signal a -> Signal s

Sinks:

main : Signal Element -- element to be rendered to screenport someJavaScriptFn : Signal String -- Send strings to JavaScript

BUTWHYSIGNALS?1. Naturallyhandlesasynchrony

2. Naturallymodeldataovertimewhileavoidingshared

mutablestate

IA:FRPSTREAMSINJSContenders:

RxJS(Biggest)

Bacon.js(Slowest)

Kefir.js(Middle)

Most.js(Fastest)

Flyd(Smallest)

I'lldiscussRxJS,Most,andFlyd

IA:RXJSRxJSimplementsObservables

/* Get stock data somehow */var source = getAsyncStockData() // Source is an observable

source .filter(function (quote) { // Branches return quote.price > 30 }) .map(function (quote) { return quote.price }) .subscribe(function (price) { // Sink console.log('Prices higher ' + 'than $30: $' + price) })

Mostpopularbutalsothelargestfilesize(around200kb

minified)

CanchooseasynchronybetweensetImmediate,

setTimeout,requestAnimationFrame

IA:MOST.JSMonadicStreams

most.from([1, 2, 3, 4]) .delay(1000) .filter(function(i) { return i % 2 === 0 }) .reduce(function(result, y) { return result + y }, 0) .then(function(result) { console.log(result) })

Superfastandaround50kbminified,uncompressed

Consumingfunctions(reduce,forEach,observe)

returnPromises.

IA:FLYDPronouncedflu(it'sDutch)

var x = flyd.stream(10) // Create stream with initial valuevar y = flyd.stream(20)

var sum = flyd.combine(function(x, y) { return x() + y() // Calling stream without argument returns last value}, [x, y])

flyd.on(function(s) { console.log(s)}, sum)

VerySimple.ModeledafterElmSignals.

Mostlyjustgiveslow-levelcompositionconstructse.g.

combine,merge,transduce

ABSTRACTINGAWAY

SIDE-EFFECTSTasks

Effects

IA:Promises

TASKStype Task x a

Representsasynchronouseffectsthat

returnvalueoftypeabutmayfailwith

valueoftypex.

SoundlikePromises?Theyareevenchainablewith

andThen:

logCurrentTime : Task x ()logCurrentTime = getCurrentTimeTask `andThen` consoleLogTask

EFFECTStype Effects a

TheEffectstypeisessentiallyadata

structureholdingabunchofindependent

tasksthatwillgetrunatsomelaterpoint.

ExamplemakinganHTTPrequestforjsonData:

getData : String -> Effects ActiongetData url = Http.get decodeJsonData url |> Task.toMaybe |> Task.map NewGif |> Effects.task

EXPLAINEDtype Action = NewGif (Maybe String) | ... -- some other action

getData : String -> Effects ActiongetData url = Http.get decodeJsonData url |> Task.toMaybe |> Task.map NewGif |> Effects.task

Task.toMaybedropstheerrormessageandreturnsa

Maybe Stringtype.

Task.map NewGifwrapstheMaybe Stringina

NewGifaction.

Effects.taskturnthistaskintoanEffectstype.

TASK,MAYBE,EFFECTS

OHMY!EffectswrapTasksthatareguaranteedto"notfail"...

meaningtheyhaveanerrorhandler.

Task.toMaybeandTask.toResultareconvenience

functionstomoveerrorsintothesuccesshandlerby

returninganewtask.

toMaybe : Task x a -> Task y (Maybe a)toMaybe task = map Just task `onError` (\_ -> succeed Nothing)

toResult : Task x a -> Task y (Result x a)toResult task = map Ok task `onError` (\msg -> succeed (Err msg))

WHYAREEFFECTS

USEFUL?Thoughts?

WHYAREEFFECTS

USEFUL?Mytheory:tomakethestart-apppackagebetter!

Ifyoucancollectthetasksforallyourcomponentsthatwill

berendered,youcanruntheminabatchbutonlyifthey

neverfail.

IA:PROMISESvar p = new Promise(function(resolve, reject) { // something async happens});

p.then(successHandlerFn, failureHandlerFn);

WhatcanwelearnfromElm?

Don'trejectpromisesneedlessly

var p = new Promise(function (resolve, reject) { doAsync(function (err, result) { if (err) { return resolve({status: 'failed', data: err}) } resolve({status: 'success', data: result}) })})

SUM-UPTryoutElm

Or:

Useflowforstatictypeanalysis

UseaJavaScriptFRPLibrary

UsePromisesthat"neverfail"

Morerealistically,usesomecombinationoftheabove;)


Recommended