-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
530 lines (375 loc) · 10.6 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
<!DOCTYPE html>
<html>
<head>
<title>What is Elm and Why Should I care?</title>
<meta charset="utf-8">
<style>
@import url(https://fonts.googleapis.com/css?family=Yanone+Kaffeesatz);
@import url(https://fonts.googleapis.com/css?family=Droid+Serif:400,700,400italic);
@import url(https://fonts.googleapis.com/css?family=Ubuntu+Mono:400,700,400italic);
body { font-family: 'Droid Serif'; }
h1, h2, h3 {
font-family: 'Yanone Kaffeesatz';
font-weight: normal;
}
h1, p, li, .remark-slide-number {
color: white;
}
h2 {
color: whitesmoke;
}
h3 {
color: aquamarine;
}
.remark-slide-content {
background-color: black;
}
strong {
color: #D69090;
}
em {
color: #97B0E8;
}
a, a:visited {
color: #97B0E8;
text-decoration: none;
}
.small {
width: 200px;
}
blockquote > p {
color: #B3F9E1;
}
.remark-code, .remark-inline-code { font-family: 'Ubuntu Mono'; }
</style>
</head>
<body>
<textarea id="source">
class: center, middle
# What is Elm and Why Should I Care?
.center[twitter & github: @tgroshon]
---
# Direct Complaints as Follows
![trash can](https://farm1.staticflickr.com/12/17834156_aa3bc64c96_z.jpg?zz=1)
---
### Goals
1. Apply Elm's good ideas to our daily work
2. Promote Elm as a development tool
### Agenda
1. Introduction to Elm
1. Details of How it Works
2. Type Analysis Advantages
2. Signals -> Values over Time
2. Abstracting Away Side-Effects
1. Sum-up
### Format
Some **persuasion** followed by an _Immediate Action (IA)_
---
# Intro: Syntax
- Haskell-like syntax
- Statically Typed
- Declarative
- Compile-to-JavaScript
```elm
import Graphics.Element exposing (..)
import Window
main : Signal Element
main =
Signal.map resizeablePaint Window.dimensions
resizeablePaint : (Int,Int) -> Element
resizeablePaint (w,h) =
fittedImage w h "/imgs/paint.jpg"
-- Types can be ommitted/inferred in most cases but are nice for Doc
```
Type Aliases
```elm
type alias Name = String
type alias Age = Int
```
---
# Intro: Tool-chain
Written in Haskell
```bash
elm-make # Compiles Elm to JS
elm-package # Package Manager
elm-repl # A Read-Eval-Print-Loop
elm-reactor # Quick-start Watcher/Builder
elm # Wrapper around all the tools
```
## Other tools
- Webpack Loader: _https://github.com/rtfeldman/elm-webpack-loader_
- `elm-make` JS Bindings: _https://github.com/rtfeldman/node-elm-compiler_
---
# The Type Analysis Advantage
### This just in: Dynamic types are out, Static types are in!
- Advantages of Elm's Type System
+ Catch Simple **Errors**
+ Banish **Nulls**
+ **Enforce** Semantic Versioning
- _IA: Flow_
---
# The Simple Errors
Goodbye spelling mistakes and refactoring lapses:
![Elm error messages](http://elm-lang.org/assets/blog/error-messages/0.15.1/naming.png)
---
# Banish Null
> I call it my billion-dollar mistake. It was the invention of the null reference in 1965.
_- Tony Hoare (Builder of Algol W)_
No nulls in Elm, Just Maybes:
```elm
type Maybe a = Just a | Nothing
```
Allows the compiler to enforce "null-checks" when needed.
---
# Enforcing Semantic Versioning
elm-package will bump versions for you, automatically enforcing these rules:
- all packages start with initial version 1.0.0
- Versions are incremented based on how the API changes:
+ PATCH - the API is the same, no risk of breaking code
+ MINOR - values have been added, existing values are unchanged
+ MAJOR - existing values have been changed or removed
Even Rust-lang is talking about adding similar checks: https://users.rust-lang.org/t/signature-based-api-comparison/2377
---
# IA: Flow
.center[flowtype.org]
```javascript
/* @flow */
function foo(x) {
return x * 10;
}
foo('Hello, world!'); // Error: This type is incompatible with ...: string
```
```javascript
/* @flow */
function foo(x: string, y: number): string {
return x.length * y;
}
foo('Hello', 42); // Error: number ... type is incompatible with ... string
```
Babel will strip it out for you:
_http://babeljs.io/docs/plugins/transform-flow-strip-types/_
---
# One Beef with Flow
> In JavaScript, null implicitly converts to all the primitive types; it is also a valid inhabitant of any object type.
>
> In contrast, Flow considers null to be a distinct value that is not part of any other type.
- Let's be Honest: In JavaScript, _all types are nullable_!
- Requires programmer discipline to be honest about which vars are _not_ Maybe (fewer than we think)
- Not a great decision for a gradually-typed system over a language with nullable types
## Recommendation
**As a habit in flow, mark things as Maybe**
---
# Signals -> Values Over Time
- Discrete values over time
- Signal Graphs
- _IA: RxJS, Most.js, Flyd_
---
# Discrete Values Over Time
```elm
type Signal a
```
> A value that changes over time. Every signal is updated at discrete
> moments in response to events in the world.
So like an EventEmitter? Almost, and not quite.
The **Reactive** in Elm _Functional-Reactive Programming_
---
# Signal Characteristics
- **Synchronous**: FIFO
- **Infinite & Static**: You **cannot** _delete_, _create_, or _unsubscribe_ from signals at runtime.
---
# Signal Graph
Your program ends up being a graph of signals.
Think of pipes (streams):
(a) sources, (b) branches, and (c) sinks.
![Elm signal Diagram](http://elm-lang.org/assets/diagrams/signals.png)
---
# Signal Graph (cont'd)
An Application's signal graph can have multiple sources, branches, and sinks.
Sources:
```elm
position : Signal (Int, Int) -- Mouse
clicks : Signal () --
dimensions : Signal (Int, Int) -- Window
```
Branches (Transforms):
```elm
map : (a -> b) -> Signal a -> Signal b
filter : (a -> Bool) -> a -> Signal a -> Signal a
merge : Signal a -> Signal a -> Signal a
foldp : (a -> s -> s) -> s -> Signal a -> Signal s
```
Sinks:
```elm
main : Signal Element -- element to be rendered to screen
port someJavaScriptFn : Signal String -- Send strings to JavaScript
```
---
# But Why Signals?
1. Naturally handles _asynchrony_
1. Naturally model _data over time_ while avoiding shared mutable state
---
# IA: FRP Streams in JS
Contenders:
* RxJS (**Biggest**)
* Bacon.js (_Slowest_)
* Kefir.js (**Middle**)
* Most.js (_Fastest_)
* Flyd (**Smallest**)
I'll discuss _RxJS_, _Most_, and _Flyd_
---
# IA: RxJS
RxJS implements *Observables*
```javascript
/* 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)
})
```
Most popular but also the largest file size (around **200kb** minified)
Can choose asynchrony between `setImmediate`, `setTimeout`, `requestAnimationFrame`
---
# IA: Most.js
_Monadic_ Streams
```javascript
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)
})
```
Super fast and around **50kb** minified, uncompressed
Consuming functions (`reduce`, `forEach`, `observe`) return Promises.
---
# IA: Flyd
Pronounced _flu_ (it's Dutch)
```javascript
var x = flyd.stream(10) // Create stream with initial value
var 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)
```
Very Simple. Modeled after Elm Signals.
Mostly just gives low-level composition constructs e.g. `combine`, `merge`, `transduce`
---
# Abstracting Away Side-Effects
- Tasks
- Effects
- _IA: Promises_
---
# Tasks
```elm
type Task x a
```
> Represents asynchronous effects that return value of type **a** but _may fail_ with value of type **x**.
Sound like Promises? They are even chainable with `andThen`:
```elm
logCurrentTime : Task x ()
logCurrentTime =
getCurrentTimeTask `andThen` consoleLogTask
```
---
# Effects
```elm
type Effects a
```
> The Effects type is essentially a data structure holding a bunch of independent tasks that will get run at some later point.
Example making an HTTP request for jsonData:
```elm
getData : String -> Effects Action
getData url =
Http.get decodeJsonData url
|> Task.toMaybe
|> Task.map NewGif
|> Effects.task
```
---
# Explained
```elm
type Action = NewGif (Maybe String) | ... -- some other action
getData : String -> Effects Action
getData url =
Http.get decodeJsonData url
|> Task.toMaybe
|> Task.map NewGif
|> Effects.task
```
- **`Task.toMaybe`** drops the error message and returns a `Maybe String` type.
- **`Task.map NewGif`** wraps the `Maybe String` in a `NewGif` action.
- **`Effects.task`** turn this task into an `Effects` type.
---
# Task, Maybe, Effects Oh My!
Effects wrap Tasks that are guaranteed to "not fail" ... meaning they have an _error handler_.
**`Task.toMaybe`** and **`Task.toResult`** are _convenience functions_ to move errors into
the success handler by returning a new task.
```elm
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))
```
---
# Why are Effects useful?
Thoughts?
---
# Why are Effects useful?
My theory: to make the `start-app` package better!
If you can collect the tasks for all your components that will be rendered,
you can run them in a batch _but only if they **never fail**_.
---
# IA: Promises
```javascript
var p = new Promise(function(resolve, reject) {
// something async happens
});
p.then(successHandlerFn, failureHandlerFn);
```
What can we learn from Elm?
**Don't reject promises needlessly**
```javascript
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-up
- Try out Elm
- Or:
+ Use flow for static type analysis
+ Use a JavaScript FRP Library
+ Use Promises that "never fail"
More realistically, use some combination of the above ;)
</textarea>
<script src="https://gnab.github.io/remark/downloads/remark-latest.min.js">
</script>
<script>
var slideshow = remark.create();
</script>
</body>
</html>