# JavsScript中的函数式编程

var fact = function(n) {
if (n <= 1) {
return 1;
}
return n * fact(n-1);
};

var tail_fact = function(n, acc) {
if (n == 0) {
return 1;
} else if (n == 1) {
return acc;
}
return tail_fact(n-1, n*acc);
};


var member = function(x, list) {
if (list.length === 0) return false;
if (x === list.shift()) return true;
return member(x, list);
};


2.1 Map

Map用于对数组中的每一个元素应用传入的函数，并将结果作为一个新的数组返回。我第一次接触Map函数是在Pike语言中，当时在一家移动互联网领域的初创公司实习，公司的服务器端是使用Pike写的，想起来那时我对函数式编程还一无所知呢。

var map = function(fn, xs) {
if (xs.length === 0)
return [];
return [fn(xs.shift())].concat(map(fn, xs));
};


var res = map(function(x) {
return x+1;
}, [1, 2, 3, 4, 5, 6]);
console.log(res); // [2, 3, 4, 5, 6, 7]


Array.prototype.map = function(fun) {
if (this === void 0 || this === null)
throw new TypeError();

var t = Object(this);
var len = t.length >>> 0;
if (typeof fun !== "function")
throw new TypeError();

var res = new Array(len);
var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
for (var i = 0; i < len; i++) {
if (i in t)
res[i] = fun.call(thisArg, t[i], i, t);
}
return res;
};

// Use the build-in map
var res = [1, 2, 3, 4, 5].map(function(x) {
return x+1;
};


2.2 Reduce

Reduce在其他函数式语言中又被称作fold，

var reduce = function(f, xs, acc) {
if (acc === void 0)
acc = 0;
if (xs.length === 0)
return acc;
return reduce(f, xs.slice(1), f(acc, xs.shift()));
};


var res = reduce(function(x, y) {
return x+y;
}, [1, 2, 3, 4, 5], 0);


var res = reduce(function(x, y) {
return x && y>= 0;
}, [1, -2, 3, -4, 5], true);


var checkArray = function(g, xs) {
return reduce(function(x, y) {
return x && g(y);
}, xs, true);
};


var t = checkArray(function(x) {
return x.length <= 5;
}, ['hello', 'javascript']); // false


var numberInRange = function(xs, low, high) {
return reduce(function(x, y) {
if (y >= low && y <= high) {
return x + 1;
}
return x;
}, xs);
};

console.log(numberInRange([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 3, 8)); // 6


2.3 Filter

Filter顾名思义就是对数组中的元素进行过滤，留下符合条件的元素组成新数组返回。

var filter = function(fn, xs) {
if (xs.length === 0)
return [];
if (fn(x = xs.shift()))
return [x].concat(filter(fn, xs));
return filter(fn, xs);
}


Filter对数组中每一个元素使用fn进行判断，只有判断结果为true的元素才会保留下来。

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
res = myfilter(function(x) {
return x%2===0;
}, arr);
console.log(res); // [2, 4, 6, 8, 10]


Function.prototype.curry = function() {
var slice = Array.prototype.slice,
args = slice.apply(arguments),
that = this;
return function() {
return that.apply(null, args.concat(slice.apply(arguments)));
};
};