Slide 1

Slide 1 text

Functional programming in JavaScript ecosystem

Slide 2

Slide 2 text

JS is a functional language

Slide 3

Slide 3 text

JS is a functional language Sort of...

Slide 4

Slide 4 text

What do we have today

Slide 5

Slide 5 text

What do we have today Proper anonymous functions (λ) Closures ES5 array extras (map, filter, reduce...)

Slide 6

Slide 6 text

Is it enough?

Slide 7

Slide 7 text

Is it enough? Yep.

Slide 8

Slide 8 text

Is it comfy?

Slide 9

Slide 9 text

Nope. Is it comfy?

Slide 10

Slide 10 text

What’s wrong?

Slide 11

Slide 11 text

What’s wrong? keywords are too long

Slide 12

Slide 12 text

What’s wrong? braces everywhere keywords are too long

Slide 13

Slide 13 text

What’s wrong? braces everywhere keywords are too long no static types

Slide 14

Slide 14 text

What’s wrong? braces everywhere keywords are too long no static types no proper tail calls

Slide 15

Slide 15 text

What’s wrong? keywords are too long braces everywhere this scoping problem s no static types no proper tail calls

Slide 16

Slide 16 text

What’s wrong? keywords are too long braces everywhere this scoping problem s no constants no static types no proper tail calls

Slide 17

Slide 17 text

What’s wrong? ES5 array extras work alright in chaining But Prototype-based == awful modularity == collisions == low performance

Slide 18

Slide 18 text

Solutions? I want to write functionally in JS ecosystem simply. What are my options?

Slide 19

Slide 19 text

Solutions? haskell-to-js ClojureScript

Slide 20

Slide 20 text

Solutions? haskell-to-js ClojureScript Compile to very long files hard to debug Terrible interoperability

Slide 21

Slide 21 text

Solutions? Readable / reasonable JS output? Good interoperability? Simple to debug?

Slide 22

Slide 22 text

CoffeeScript coffeescript.org

Slide 23

Slide 23 text

CoffeeScript Great small language Compiles down to JS #11 most used on GitHub Used in 1000s of popular projects

Slide 24

Slide 24 text

CoffeeScript Better for functional programming Heals JS quirks

Slide 25

Slide 25 text

CoffeeScript Implicit return Short λ declaration (a, b, c) -> a * b / c function(a, b, c) { return a * b / c; } vs Whitespace-significant syntax

Slide 26

Slide 26 text

CoffeeScript No curly braces times 2, sum 1, 2, 3 # => 12 Round braces are optional times(2, sum(1, 2, 3)) # => 12

Slide 27

Slide 27 text

CoffeeScript List comprehensions (a * 2 for a in [10, 20, 40])

Slide 28

Slide 28 text

CoffeeScript this fixes via bound functions current = this fn = => log current == this $(‘body’).on ‘click’, fn # Will log true var current = this; var fn = function() { log current == this; }; $(‘body’).on ‘click’, fn # Will log false

Slide 29

Slide 29 text

CoffeeScript Doesn’t heal all quirks Brings own ones

Slide 30

Slide 30 text

CoffeeScript Chaining is a lot readable with short λs, but still terrible # Doesn’t work on Array-like objects document.querySelectorAll(‘.user’) .map((x) -> x + 5) .maximum() # Defining methods on prototypes? No, thanks.

Slide 31

Slide 31 text

CoffeeScript Must create λs even for simple stuff array .map((a) => a + 2) .filter((a) => a != 10) .reduce((a, b) => Math.min(a, b)) the only real work

Slide 32

Slide 32 text

CoffeeScript List comprehensions aren’t real Basically an infix for loop (a * b for a in [1, 2, 3] for b in [10, 20, 40]) # non flattened result, order is wrong # => [ [ 10, 20, 30 ], [ 20, 40, 60 ], [ 40, 80, 120 ] ]

Slide 33

Slide 33 text

CoffeeScript variable = 1 fn = -> variable = 2 fn() console.log variable # => 2 Terrible variable scoping

Slide 34

Slide 34 text

Roy roy.brianmckenna.org

Slide 35

Slide 35 text

Roy Type inference Algebraic data types Pattern matching Monadic syntax

Slide 36

Slide 36 text

Roy Not ready yet Still a lot of stuff it doesn’t have

Slide 37

Slide 37 text

LiveScript gkz.github.com/ LiveScript/

Slide 38

Slide 38 text

LiveScript + = + = + = Coco Coco

Slide 39

Slide 39 text

LiveScript Easy transition from Coffee Improved readability Perfect piping operators |> (F#) <| (F#) ($ in Haskell)

Slide 40

Slide 40 text

LiveScript Standard library (prelude.ls) gkz.github.com/ prelude-ls/ Inspired by prelude.hs

Slide 41

Slide 41 text

LiveScript Partially applied operators and member access array |> map (+ 2) |> filter (!= 10) |> maximum

Slide 42

Slide 42 text

LiveScript Compile-time consants Also, compiler flag that make all vars consts const string = ‘hello’ string = 5710 # => Error

Slide 43

Slide 43 text

LiveScript Improved var scoping a = 1 do -> a = 2 a # => still 1

Slide 44

Slide 44 text

LiveScript Improved operators associativity unique pulls .length unique node or not empty node (unique pulls).length (unique node) or not (empty node) instead of coffee’s

Slide 45

Slide 45 text

LiveScript Real list comprehensions [x ** y for x in [10, 20] for y in [2, 3]] # => [100, 1000, 400, 800]

Slide 46

Slide 46 text

LiveScript Pattern matching take(n, [x, ...xs]:list) = | n <= 0 => [] | empty list => [] | otherwise => [x] +++ take n - 1, xs

Slide 47

Slide 47 text

LiveScript Simple currying times = (x, y) --> x * y times 2, 3 # => 6 double = times 2 double 5 # => 10

Slide 48

Slide 48 text

LiveScript Async callback flattening syntax error <- fs.write-file path, data

Slide 49

Slide 49 text

LiveScript Is it ready to use today?

Slide 50

Slide 50 text

LiveScript Is it ready to use today? Yep! 1.0.0 will be released later this week.

Slide 51

Slide 51 text

LiveScript Relatively simple Debugging Will be super simple with source maps (2012)

Slide 52

Slide 52 text

LiveScript Sure! HTML5 apps Including builders that auto-compile your apps without headache (Brunch.io).

Slide 53

Slide 53 text

LiveScript Yep. Node.js Just add pre-publish hook to `package.json`

Slide 54

Slide 54 text

Compare

Slide 55

Slide 55 text

Compare users |> map (.age) |> filter (> 10) |> maximum users .map((u) -> u.age) .filter((a) -> a > 10) .reduce (a, b) -> Math.max a, b users .map(function(u) {return u.age}) .filter(function(a) {return a > 10}) .reduce(function(a, b) { return Math.max(a, b) }); JS Coffee LiveScript (w/prelude)

Slide 56

Slide 56 text

Compare Coffee LiveScript elems = document.query-selector-all '.listing .meta a:nth-child(3)' pulls = elems |> map (.inner-text) text = "Total #{pulls.length} pull requests in #{unique pulls .length} repos." elems = [].slice.call document.querySelectorAll '.listing .meta a:nth-child(3)' pulls = elems.map (elem) -> elem.innerText unique = elems.reduce (a, b) -> a.push(b) if b not in a a text = "Total #{pulls.length} pull requests in #{(unique pulls).length} repos." JS → 14 LOC

Slide 57

Slide 57 text

Compare LiveScript quick-sort = ([x, ...xs]:list) -> | empty list => [] | otherwise => [left, right] = partition (<= x), xs (quick-sort left) +++ [x] +++ (quick-sort right) gist.github.com/ 3074009

Slide 58

Slide 58 text

Compare JS Coffee LiveScript quick-sort = ([x, ...xs]:list) -> | empty list => [] | otherwise => [left, right] = partition (<= x), xs (quick-sort left) +++ [x] +++ (quick-sort right) gist.github.com/ 3074009

Slide 59

Slide 59 text

Future ECMAScript 6 CoffeeScript 2.0 LiveScript.next

Slide 60

Slide 60 text

Future: ECMAScript 6 let block-scoped vars const value checking Short arrow functions Tail call optimization Real list comprehensions New javascript standard

Slide 61

Slide 61 text

Future: ECMAScript 6 Still a lot of syntax garbage ((a, b) => {a + b})(2, 5)); (+) 2, 5 vs

Slide 62

Slide 62 text

Future: CoffeeScript 2 Same feature set Proper compiler design principles github.com/michaelficarra/ CoffeeScriptRedux

Slide 63

Slide 63 text

Future: CoffeeScript 2 github.com/michaelficarra/ coffee-of-my-dreams When it will be ready, author will create a functional fork

Slide 64

Slide 64 text

Future: LiveScript Type inference Pure annotations Tail call optimization

Slide 65

Slide 65 text

So? 1. Use LiveScript 2. Wait for fork of Coffee 2.0 3. Wait for Roy I want to write functionally in JS ecosystem simply. What are my options?

Slide 66

Slide 66 text

Thanks! Paul Miller paulmillr.com @paulmillr