jurStv
7/25/2015 - 12:16 PM

From Functional Programming in Javascript book

From Functional Programming in Javascript book

var typeOf = function(type) {
  return function(x) {
    if (typeof x === type) {
      return x;
    }
    else {
      throw new TypeError("Error: "+type+" expected, "+typeof x+" given.");
    }
  }
}
var objectTypeOf = function(name) {
  return function(o) {
    if (Object.prototype.toString.call(o) === "[object "+name+"]") {
      return o;
    }
    else {
      throw new TypeError("Error: '+name+' expected, something else given.");
    }
  }
}
var str = typeOf('string'),
  num = typeOf('number'),
  func = typeOf('function'),
  bool = typeOf('boolean'),
  obj = objectTypeOf('Object'),
  arr = objectTypeOf('Array'),
  date = objectTypeOf('Date'),
  div = objectTypeOf('HTMLDivElement');
  
  
// unprotected method:
var x = '24';
x + 1; // will return '241', not 25
// protected method
// plusplus :: Int -> Int
function plusplus(n) {
  return num(n) + 1;
}
plusplus(x); // throws error, preferred over unexpected output
var trampoline = function(f) {
  while (f && f instanceof Function) {
    f = f.apply(f.context, f.args);
  }
  return f;
};
var thunk = function (fn) {
  return function() {
    var args = Array.prototype.slice.apply(arguments);
    return function() { return fn.apply(this,	args); };
  };
};
var factorial	= function(n) {
  var _fact = thunk(function(x,	n)  {
    if  (n	==	0)  {
    //  base  case
      return  x;
    }
    else  {
    //  recursive	case
      return  _fact(n	*	x,  n - 1);
    }
  });
  return  trampoline(_fact(1,	n));
};
var treeTraverse  = function(trunk) {
  var _traverse = thunk(function(node)  {
    node.doSomething();
    node.children.forEach(_traverse);
  });
  trampoline(_traverse(trunk));
};

//Y-COMBINATOR

var Y = function(F) {
    return  (function (f) {
      return  f(f);
    } (function (f) {
        return  F(function  (x) {
            return  f(f)(x);
        });
    }));
};
var Ymem  = function(F, cache)  {
    if  (!cache)  {
        cache = {}  ;	//  Create  a new cache.
    }
    return  function(arg) {
        if  (cache[arg])  {
            //  Answer  in  cache
            return  cache[arg]  ;	
        }
        //  else  compute the answer
        var answer  = (F(function(n){
            return  (Ymem(F,cache))(n);
        }))(arg); //  Compute the answer.
        cache[arg]  = answer; //  Cache the answer.
        return  answer;
    };
}

var FactorialGen  = function  (factorial) {
    return  function(n) {
        var factorial = thunk(function  (x,	n)  {
            if  (n  ==  0)  {
                return  x;
            }
            else  {
                return  factorial(n * x,  n - 1);
            }
        });
        return  trampoline(factorial(1,	n));
    }
};


var	Factorial	=	Ymem(FactorialGen);
Factorial(10);	//	3628800
Factorial(23456);	//	Infinity
/*
the	most	efficient	and	safest	method	of	performing	recursion	in
JavaScript	is	to	use	the	memoizing	Y-combinator	with	tail-call	elimination	
via trampolining	and	thunks.
*/
/*
Promises are like the functional equivalent of callbacks. Obviously, callbacks are not all
that functional because, if more than one function is mutating the same data, then there
can be race conditions and bugs. Promises solve that problem.
*/
// the Promise monad
var Promise = require('bluebird');
// the promise functor
var promise = function(fn, receiver) {
  return function() {
    var slice = Array.prototype.slice,
    args = slice.call(arguments, 0, fn.length - 1),
    promise = new Promise();
    args.push(function() {
      var results = slice.call(arguments),
      error = results.shift();
      if (error) promise.reject(error);
      else promise.resolve.apply(promise, results);
    });
    fn.apply(receiver, args);
    return promise;
  };
};
//Now we can use the promise() functor to transform functions 
//that take callbacks into functions that return promises.
var files = ['a.json', 'b.json', 'c.json'];
readFileAsync = promise(fs.readFile);
var data = files
  .map(function(f){
    readFileAsync(f).then(JSON.parse)
  })
  .reduce(function(a,b){
    return $.extend({}, a, b)
  });
/*
Lenses are first-class getters and setters. They allow us to not just get and set variables,
but also to run functions over it. But instead of mutating the data, they clone and return the
new data modified by the function. They force data to be immutable, which is great for
security and consistency as well for libraries. They’re great for elegant code no matter
what the application, so long as the performance-hit of introducing additional array copies
is not a critical issue.
Before we write the lens() function, let’s look at how it works.

*/

var first = lens(
  function (a) { return arr(a)[0]; }, // get
  function (a, b) { return [b].concat(arr(a).slice(1)); } // set
);
first([1, 2, 3]); // outputs 1
first.set([1, 2, 3], 5); // outputs [5, 2, 3]
function tenTimes(x) { return x * 10 }
first.modify(tenTimes, [1,2,3]); // outputs [10,2,3]

//And here’s how the lens() function works. 
//It returns a function with get, set and mod defined. 
//The lens() function itself is a functor.
var lens = function (get, set) {
  var f = function (a) {return get(a)};
  f.get = function (a) {return get(a)};
  f.set = set;
  f.mod = function (f, a) {return set(a, f(get(a)))};
  return f;
};
// userName :: User -> str
var userName = lens(
function (u) {return u.getUsernameMaybe()}, // get
function (u, v) { // set
u.setUsername(v);
return u.getUsernameMaybe();
}
);
var bob = new User();
bob.setUsername('Bob');
userName.get(bob); // returns 'Bob'
userName.set(bob, 'Bobby'); //return 'Bobby'
userName.get(bob); // returns 'Bobby'
userName.mod(strToUpper, bob); // returns 'BOBBY'
strToUpper.compose(userName.set)(bob, 'robert'); // returns 'ROBERT'
userName.get(bob); // returns 'robert'
/*
Monads are tools that help you compose functions.
Like primitive types, monads are structures that can be used as the containers 
that functors “reach into”. The functors grab the data, do something to it, 
put it into a new monad, and return it.
There are three monads we’ll focus on:
Maybes
Promises
Lenses

...
jQuery, the popular JavaScript library that provides an
enhanced interface for working with HTML is, in-fact, a monadic library.
The jQuery object is a monad and its methods are functors. 
Really, they’re a special type of functor called endofunctors. 
Endofunctors are functors that return the same category as the input, that is, 
F :: X -> X. Each jQuery method takes a jQuery object and returns a
jQuery object, which allows methods to be chained, 
and they will have the type signature
jFunc :: jquery-obj -> jquery-obj.

Monads are the containers that the functors “reach into” to get the data. 
In this way, the data can be protected and controlled by the library. 
jQuery provides access to the underlying data, a wrapped set of HTML elements, 
via its many methods.

*/
/*
First, we’ll need a function that helps us create morphisms. 
We’ll call it homoMorph() because they’ll be homomorphisms. 
It will return a function that expects a function to be
passed in and produces the composition of it, based on the inputs. 
The inputs are the types that the morphism accepts as input and gives as output.
*/

var homoMorph = function( /* input1, input2,..., inputN, output */ ) {
  var before = checkTypes(arrayOf(func)
  (Array.prototype.slice.call(arguments, 0, arguments.length-1)));
  var after = func(arguments[arguments.length-1])
  return function(middle) {
    return function(args) {
      return after(middle.apply(this, before([].slice.apply(arguments))));
    }
  }
}

// now we don't need to add type signature comments
// because now they're built right into the function declaration
add = homoMorph(num, num, num)(function(a,b){return a+b})
add(12,24); // returns 36
add('a', 'b'); // throws error
homoMorph(num, num, num)(function(a,b){
  return a+b;
})(18, 24); // returns 42

/*
It uses a closure to return a function that accepts a function
and checks its input and output values for type safety.
*/
var checkTypes = function( typeSafeties ) {
  arrayOf(func)(arr(typeSafeties));
  var argLength = typeSafeties.length;
  return function(args) {
    arr(args);
    if (args.length != argLength) {
      throw new TypeError('Expected '+ argLength + ' arguments');
    }
    var results = [];
    for (var i=0; i<argLength; i++) {
      results[i] = typeSafeties[i](args[i]);
    }
    return results;
  }
}
//Now let’s formally define some homomorphisms.
var lensHM = homoMorph(func, func, func)(lens);
var userNameHM = lensHM(
  function (u) {return u.getUsernameMaybe()}, // get
  function (u, v) { // set
    u.setUsername(v);
    return u.getUsernameMaybe();
  }
);
var strToUpperCase = homoMorph(str, str)(function(s) {
  return s.toUpperCase();
});
var morphFirstLetter = homoMorph(func, str, str)(function(f, s) {
  return f(s[0]).concat(s.slice(1));
});
var capFirstLetter = homoMorph(str, str)(function(s) {
return morphFirstLetter(strToUpperCase, s)
});
//The following example includes function composition, lenses, homomorphisms, and more
// homomorphic lenses
var bill = new User();
userNameHM.set(bill, 'William'); // Returns: 'William'
userNameHM.get(bill); // Returns: 'William'
// compose
var capatolizedUsername = fcompose(capFirstLetter,userNameHM.get);
capatolizedUsername(bill, 'bill'); // Returns: 'Bill'
// it's a good idea to use homoMorph on .set and .get too
var getUserName = homoMorph(obj, str)(userNameHM.get);
var setUserName = homoMorph(obj, str, str)(userNameHM.set);
getUserName(bill); // Returns: 'Bill'
setUserName(bill, 'Billy'); // Returns: 'Billy'
// now we can rewrite capatolizeUsername with the new setter
capatolizedUsername = fcompose(capFirstLetter, setUserName);
capatolizedUsername(bill, 'will'); // Returns: 'Will'
getUserName(bill); // Returns: 'will'

/*
What does it mean for code to be declarative? In imperative programming, we write
sequences of instructions that tell the machine how to do what we want. 
In functional programming, we describe relationships between values 
that tell the machine what we want it to compute, and the machine figures out 
the instruction sequences to make it happen. 
Functional programming is declarative.
*/
/*
While morphisms are mappings between types, functors are mappings 
between categories. They can be thought of as functions that lift values out 
of a container, morph them, and then put them into a new container. 
The first input is a morphism for the type and the second input is the container.
The type signature for functors looks like this:
myFunctor :: (a -> b) -> f a -> f b
It turns out we already have one functor: map(). 
It grabs the values within the container, an array, and applies a function to it.
*/
// map :: (a -> b) -> [a] -> [b]
var map = function(f, a) {
  return arr(a).map(func(f));
}
var strmap = function(f, s) {
  return str(s).split('').map(func(f)).join('');
}


// arrayOf :: (a -> b) -> ([a] -> [b])
var arrayOf = function(f) {
  return function(a) {
    return map(func(f), arr(a));
  }
}
var plusplusall = arrayOf(plusplus); // plusplus is our morphism
console.log( plusplusall([1,2,3]) ); // returns [2,3,4]
console.log( plusplusall([1,'2',3]) ); // error is thrown

var strs = arrayOf(str);
console.log( strs(['a','b','c']) ); // returns ['a','b','c']
console.log( strs(['a',2,'c']) ); // throws error
var fcompose = function() {
  // first make sure all arguments are functions
  var funcs = arrayOf(func)(arguments);
  // return a function that applies all the functions
  return function() {
    var argsOfFuncs = arguments;
    for (var i = funcs.length; i > 0; i -= 1) {
      argsOfFuncs = [funcs[i].apply(this, args)];
    }
    return args[0];
  };
};
// example:
var f = fcompose(negate, square, mult2, add1);
f(2); // Returns: -36

var curry = function(f) {
  var recur;
	var __slice = [].slice;
  return (recur = function(as) {
    var next;
    next = function() {
      var args, bs;
      bs = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
      args = (as || []).slice(0);
      if (args.push.apply(args, bs) < f.length && bs.length) {
        return recur(args);
      }
      return f.apply(null, args);
    };
    if (f.length > 1) {
      return next;
    } else {
      return f;
    }
  })();
};
/*
 Here are five different implementations of the same floorSqrt() 
functional composition.
 They seem to be identical, but they deserve scrutiny.
 But there are a few key differences we should go over:
 Obviously the first method is verbose and inefficient.
 The second method is a nice one-liner, but this approach becomes very unreadable
after only a few functions are applied.
 The third approach is a chain of array functions, notably the map function. This works
fairly well, but it is not mathematically correct.
 Here’s our compose() function in action. All methods are forced to be unary, pure
functions that encourage the use of better, simpler, and smaller functions that do one
thing and do it well.
 The last approach uses the compose() function in reverse sequence, which is just as
valid.
*/

function floorSqrt1(num) {
  var sqrtNum = Math.sqrt(num);
  var floorSqrt = Math.floor(sqrtNum);
  var stringNum = String(floorSqrt);
  return stringNum;
}
function floorSqrt2(num) {
  return String(Math.floor(Math.sqrt(num)));
}
function floorSqrt3(num) {
  return [num].map(Math.sqrt).map(Math.floor).toString();
}
var floorSqrt4 = String.compose(Math.floor).compose(Math.sqrt);
var floorSqrt5 = Math.sqrt.sequence(Math.floor).sequence(String);
// all functions can be called like this:
floorSqrt/*<N>*/(17); // Returns: 4