LiveScript presentation – by Ankit Shukla && Aun Rizvi



LiveScript presentation – by Ankit Shukla && Aun Rizvi

1 5


LiveScript---presentation

livescript for gangsters

On Github arey0pushpa / LiveScript---presentation

LiveScript presentation

by Ankit Shukla && Aun Rizvi

We work On JavaScript

Javascript Again ?

A TRIP DOWN MEMORY LANE...

In 10 days ! ♥ Had to look like Java ♥ Be dynamic ♥ Have objects without classes ♥ Scheme functional side ♥ Self object side (prototype-based objects)

Problems with Javascript

1. JavaScript sucks : The depths to which JavaScript sucks is well-documented and well-understood.2. We need JavaScript : Using it for what it is good for, i.e. providing a platform for browser development. Lisp in C clothing ; community recently understood its functional power

The functional side of Javascript

  • Functions as first-class citizens
  • map, reduce and filter only recently arrived in the language
  • But not available in all browsers (IE <= 8)
  • Where's the rest ?

Underscore.js ?

  • "is a utility-belt library for JavaScript that provides a lot of the functional programming support [...] "
  • Cross-browser*
  • The "Most Depended Upon" lib on npm
_.map, _.reduce, _.pluck, _.debounce, _.memoize
// lot of goodies inside
* : Almost, its fork Lo-Dash is better.

Underscore, but...

  • Not that functional : currying ? order of arguments ? composition ? extensibility ? Check this talk (and the slides)
_.curry() // doesn't exist, even though _.partial exists
_.map(collection, fun) // why not the opposite order ?
_.compose(*functions) // not that useful because of previous points
					

CoffeeScript, maybe ?

# CoffeeScript
f = (a, b) ->
	a + b
// Resulting Javascript
var f = function(a, b) {
	return a + b;
};
					

Tries to push a more functional style, but doesn't go far enough...

Some CoffeeScript's features : - all functions return their last statement - almost everything is an expression - for comprehensions - default arguments - object desctructuring - sugar for classes (bof...)

Enter LiveScript

LiveScript is a fork of Coco An indirect descendant of CoffeeScript Mostly compatible Inspired mainly by Haskell and F# , with a bit of LISP Full of functional idioms

Features highlight

Personal selection. LiveScript has *A LOT*

  • Easy currying
  • Partial application
  • Function composition
  • Pipes ! Unix/F#-like
  • Pattern matching
  • Backcalls
  • Prelude.ls : an underscore-like shipped with LiveScript, very rich

Similarity Comparison

CoffeeScript : Python :: TypeScript : OCaml LiveScript : Haskell :: RedScript : Ruby

Show me the code, dude!

Easy currying of user-defined functions

# No currying

    f = (a, b) -> a + b

# Easy currying, with double arrow -->

    f = (a, b) --> a + b

    g = f 1 # curried f

    g 2 # → 3

		

Partial application

A.k.a how to solve one of Underscore's problems

# using _ as a placeholder argument for data
# Operators as functions (yes!)

  biggerThanThree = _.map _, (> 3)

# [1 2 3 4 5] will be used in place of _

  biggerThanThree [1 2 3 4 5] // → [true,true,false,false,false]
					

Function composition

yes!

# Forward composition

  add-two-times-two = (+ 2) >> (* 2)
  add-two-times-two 3 # → (3+2)*2 → 10

# Backward composition

  times-two-add-two = (+ 2) << (* 2)
  times-two-add-two 3 # → (3*2)+2 → 8

# Haskell style, equivalent to <<
  
  times-two-add-two = (+ 2) . (* 2)
					
Le highlighter ne fonctionne pas encore avec LiveScript, un patch est en cours

Pipes !

Unix/F# style. Avoids nesting calls

# (.length) is a shortcut to access property

  [1 2 3] |> filter (> 2) |> (.length) # → 1
					

Pattern matching

# empty function from Prelude.ls (coming after)
# Guard syntax (|) translates to switch in JS

  sum = ([x, ...xs]:list) ->
  	| empty list => 0
  	| empty xs   => x
  	| otherwise  => x + sum xs
					
Est-ce vraiment du pattern matching ?

Bound functions

Bound functions have this lexically bound, not dynamically bound as normally.
 -    obj = new
 -     @x      = 10
 -     @normal = -> @x
 -     @bound  = ~> @x
 -
 -   obj2 = x: 5
 -   obj2.normal = obj.normal
 -   obj2.bound  = obj.bound
 - 
 -   obj2.normal! #=> 5
 -   obj2.bound!  #=> 10   
    

Backcalls

A way to avoid pyramid of callbacks in async programming

  x <- map _, [1 to 3]
  x * 2
  # → [2,4,6]
  
# Translates to

  map(function(x){
    return x * 2;
  }, [1, 2, 3]);

# the ! suppresses the return of the function

  data <-! $.get 'my-ajax-url.com'
  $ '.result' .html data
					

Improved scoping

= Always declares variable in current scope, use := for redeclaration of outer scope variables
  x = 1
  y = 1
  do ->
    x = 2
    y := 2
  x #=> 1
  y #=> 2


Prelude.ls

The missing Javascript API's, shipped with LiveScript

What you would expect from a functional language
# 60+ functions for arrays
head, first, tail, last, compact, partition, concat, <br>
intersection, scan, take-while, zip, ...

# ~15 functions for objects (maps)
keys, values, pairs-to-obj, reject, find, ...

# ~20 functions for strings
split, join, words, unwords, reverse, repeat, ...

# 30+ functions for Math (yes!)
min, max, tau, odd, even, quot, rem, sin, signum, is-it-NaN

# of course, functions functions
apply, curry, flip, fix
					

Prelude.ls

  • Easy to install : npm install -g livescript
  • Has a CLI and a REPL : lsc or livescript
It is powerful and flexible Almost all of its functions are curried.
    fold (+), 0, [1 2 3] #=> 6
    
    sum = fold (+), 0
    sum [1 2 3] #=> 6
    sum [4 5 6] #=> 15			

Redscript

# Block-like anonymous functions
  app.get '/users/:name', do |res, req|                        
  puts req.params.name                                             
  end                                                
                 
# Make constructors quack like a duck
class Duck < Animal                                            
  def init(name)                                               
    super foo, bar                                              
    @name = name                                                   
  end,                                                         

  def sayHi                                                      
    puts 'Hello!'                                                
  end                                                        
end    
   

Laziness is the mother of nine inventions out of ten.

Lazy.js

Lazy.js it a utility library for JavaScript, similar to Underscore and Lo-Dash but with one important difference: " Lazy evaluation " .

A different paradigm

Core of Lazy.js is function composition Array transformation :
   f ( [x , y , ...] ) → [ x', y', ...]
   

Map

map from Underscore:
  var array1 = [1, 2, 3, 4, 5]; 
  var array2 = _.map(array1, function(x) { return x + array1.length; });    
   
map from Lazy.js
   var array = [1, 2, 3, 4, 5]; 
   var sequence = Lazy(array).map(function(x) { return x + array.length;});
   

Asynchronous iteration

   var asyncSequence = Lazy(array)
  .async(100) // specifies a 100-millisecond interval between each element
  .map(inc)
  .filter(isEven)
  .take(20);
    
// This function returns immediately and begins iterating 
   over the sequence asynchronously.

   asyncSequence.each(function(e) {
      console.log(new Date().getMilliseconds() + ": " + e);
     });
    
Array containing 1000 integers
  var array = Lazy.range(1000).toArray();

Do things and take first 5 results :
  function square(x) { return x * x; }
  function inc(x) { return x + 1; }
  function isEven(x) { return x % 2 === 0; }
  

Underscore way :

var result = _.chain(array).map(square).map(inc).filter(isEven).take(5).value();
   
map(square): Iterates over the array & creates
             a new 1000-element array

map(inc): Iterates over the new array,creating
          another new 1000-element array

filter(isEven): Iterates over that array,creating 
                yet another new (500-element) array

take(5): All that just for 5 elements!

Escape route :

For Performance and/or efficiency , go the procedural route
var results = [];
for (var i = 0; i < array.length; ++i) {
  var value = (array[i] * array[i]) + 1;
  if (value % 2 === 0) {
    results.push(value);
    if (results.length === 5) {
      break;
    }
  }
}  
  

Lazyjs time !

var result = Lazy(array).map(square).map(inc).filter(isEven).take(5); 
 
No iteration takes place until you call each, and no intermediate arrays are created.

That's all folks !

Questions ?