SOURCE

// some suppoorted function

function inspect(x) {
  return (typeof x === 'function') ? inspectFn(x) : inspectArgs(x);
}

function inspectFn(f) {
  return (f.name) ? f.name : f.toString();
}

function inspectArgs(args) {
  return args.reduce(function(acc, x){
    return acc += inspect(x);
  }, '(') + ')';
}

function curry(fx) {
  var arity = fx.length;

  return function f1() {
    var args = Array.prototype.slice.call(arguments, 0);
    if (args.length >= arity) {
      return fx.apply(null, args);
    }
    else {
      var f2 = function f2() {
        var args2 = Array.prototype.slice.call(arguments, 0);
        return f1.apply(null, args.concat(args2)); 
      }
      f2.toString = function() {
        return inspectFn(fx) + inspectArgs(args);
      }
      return f2;
    }
  };
}

compose = function() {
  var fns = toArray(arguments),
      arglen = fns.length;

  return function(){
    for(var i=arglen;--i>=0;) {
      var fn = fns[i]
        , args = fn.length ? Array.prototype.slice.call(arguments, 0, fn.length) : arguments
        , next_args = Array.prototype.slice.call(arguments, (fn.length || 1)); //not right with *args
      next_args.unshift(fn.apply(this,args));
      arguments = next_args;
    }
    return arguments[0];
  }
}

add = curry(function(x, y) {
    return x + y;
});

match = curry(function(what, x) {
    return x.match(what);
});

replace = curry(function(what, replacement, x) {
    return x.replace(what, replacement);
});

filter = curry(function(f, xs) {
    return xs.filter(f);
});

map = curry(function map(f, xs) {
    return xs.map(f);
});

reduce = curry(function(f, a, xs) {
    return xs.reduce(f, a);
});

split = curry(function(what, x) {
    return x.split(what);
});

join = curry(function(what, x) {
    return x.join(what);
});

toUpperCase = function(x) {
    return x.toUpperCase()
};

toLowerCase = function(x) {
    return x.toLowerCase()
};

log = console.log
// =============end support


var _ = R;


// 练习 1
//==============
// 通过局部调用(partial apply)移除所有参数

// var words = function(str) {
//   return split(' ', str);
// };

var words = split(' ');
console.log('练习 1:',words('xiao sd shihou jjk'))

// 练习 1a
//==============
// 使用 `map` 创建一个新的 `words` 函数,使之能够操作字符串数组


var sentences = undefined;
var wordsArr = map(words);

log('练习 1a:', wordsArr(['xiao 2','3 snd shihou jjk']));

// 练习 2
//==============
// 通过局部调用(partial apply)移除所有参数

var filterQs = function(xs) {
  return filter(function(x){ return match(/q/i, x);  }, xs);
};
log('练习2',filterQs(['q23','a Qc']))

var f2 = filter(match(/q/i))
log('练习2 答案',f2(['q23','a Qc']))

// 练习 3
//==============
// 使用帮助函数 `_keepHighest` 重构 `max` 使之成为 curry 函数

// 无须改动:
var _keepHighest = function(x,y){ return x >= y ? x : y; };

// 重构这段代码:
var max = function(xs) {
  return reduce(function(acc, x){
    return _keepHighest(acc, x);
  }, -Infinity, xs);
};
var max2 = reduce(_keepHighest,-Infinity)
log('练习3',max([1,3,5,6,1,23]))
log('练习3-2',max2([ ])) 

// 彩蛋 1:
// ============
// 包裹数组的 `slice` 函数使之成为 curry 函数
// //[1,2,3].slice(0, 2)
var slice = undefined;
// wrap array's slice to be functional and curried.
var slice = _.curry(function(start, end, xs){ return xs.slice(start, end); });
log('cai egg', slice(0)(2)('3767'))

// 彩蛋 2:
// ============
// 借助 `slice` 定义一个 `take` curry 函数,该函数调用后可以取出字符串的前 n 个字符。
var take = undefined;
take = slice(0)
log('cai egg', take(2)('767'))

console 命令行工具 X clear

                    
>
console