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 ] ]
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
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?