Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FP curry && compose #8

Open
yangchongduo opened this issue Oct 29, 2017 · 0 comments
Open

FP curry && compose #8

yangchongduo opened this issue Oct 29, 2017 · 0 comments

Comments

@yangchongduo
Copy link
Owner

yangchongduo commented Oct 29, 2017

compose

const pipe = (...fns) => (content) => fns.reduce((prev, next) => next(prev), content)
const compose = (...fns) => (content) => fns.reduceRight((prev, next) => next(prev), content)

/**

  • curry 预加载参数;
    */
    const add = (a, b) => {
    return a + b;
    }

add.bind(null, 1).bind(null, 2)(); // => 3
add.bind(null, 1).bind(null, 3)(); // => 4
add.bind(null, 1)(2); // => 3

/*

  • 如何实现一个简单bind
  • 缺陷:只能一次预加载参数;
  • 函数的bind
  • */

// var curry = function (fn) {
// var args = [].slice.call(arguments, 1);
// return function () {
// var newArgs = args.concat([].slice.call(arguments, 1));
// return fn.apply(this, newArgs);
// };
// };
// var curry = (fn, ...args) => (...arguments) => fn.apply(this, [...args, ...arguments])

var curry = (fn, ...args) => (...arguments) => fn(...args, ...arguments);

var addCurry = curry(add, 1, 2);
var addCurry1 = curry(add);
var addCurry2 = curry(add, 1);
console.log(addCurry());
console.log(addCurry1(1, 2));
console.log(addCurry2(2));
// addCurry() //=>3

/***

  • 多次预加载参数
  • curry(fn)()()()()()
  • curry1(add)(1)(2)
  • PS:获取函数的参数总个数 和 已经获取的参数个数进行对比不停的递归
    */
function curry1(fn, args) {
	var length = fn.length;
	args = args || [];
	return function (...arguments) {
		args = [...args, ...arguments];
		return args.length < length ? curry1.call(this, fn, args) : fn.apply(this, args);
	}
}

console.log(curry1(add)(1)(2));

/**

  • 实战
    */
function ajax(type, url, data) {
	var xhr = new XMLHttpRequest();
	xhr.open(type, url, true);
	xhr.send(data);
}

// 虽然 ajax 这个函数非常通用,但在重复调用的时候参数冗余
ajax('POST', 'www.test.com', "name=kevin")
ajax('POST', 'www.test2.com', "name=kevin")
ajax('POST', 'www.test3.com', "name=kevin")

// 利用 curry
var ajaxCurry = curry(ajax);

// 以 POST 类型请求数据
var post = ajaxCurry('POST');
post('www.test1.com', "name=kevin");
post('www.test2.com', "name=kevin");

// 以 POST 类型请求来自于 www.test.com 的数据
var postFromTest = post('www.test.com');
postFromTest("name=kevin");
postFromTest("name=xxx");

/**

  • curry 的这种用途可以理解为:预加载参数,参数复用,提高适用性。
  • 当时正真完全用函数式思想写代码的时候,柯里化是非常常见的;
    */

/**

  • 函数组装以便顺序执行
  • 1:回调
  • 2:promise then
  • 3:async await
    */

const g = n => n + 1;
const f = n => n * 2;
const e = n => n - 1;

const gData = g(10);
const fData = f(gData)
console.log('fData', fData);
/**

  • 从右到左执行 f(g(x)) || g(f(x)) 本质:从内到外的执行
  • 缺点:只支持两个函数组合。
  • @param f
  • @param g
  • @returns {Function}
    */

var compose = function (f, g) {
return function (x) {
return f(g(x));
};
};
console.log(compose(f, g)(10));
console.log(compose(g, compose(f, e))(10));

// 这是两个函数组装,如果多个呢? compose(d, compose(c, compose(b, a))) 太难读了
// compose(d, c, b, a)

/**

  • 函数式编程库
  • underscore 的 compose函数式编程库
  • lodash/fp
  • ramda.js
  • 倒叙
  • */
var compose = function () {
	var args = arguments;
	var start = args.length - 1;
	return function () {
		var i = start;
		var result = args[start].apply(this, arguments);
		while (i--) result = args[i].call(this, result);
		return result;
	};
};

// 从右 => 左
console.log(compose(g, f)(10));
console.log(compose(g, f, e)(10));

/* 注意这当中的回调函数 (prev, curr) => prev + curr

  • 与我们redux当中的reducer模型 (previousState, action) => newState
    */
[0, 1, 2, 3, 4].reduce((prev, curr) => prev + curr);

const pipe = (...fns) => x => fns.reduce((acc, fn) => fn(acc), x);
var compose = (...fns) => x => fns.reduceRight((acc, fn) => fn(acc), x);
//
// var compose = function (...fns){
// 	return function (x) {
// 		return fns.reduce(function (acc,fn) {
// 			fn(acc)
// 		},x)
// 	}
// };

// pipe(a,b)('rrr').then((res)=>{
// 	console.log(res)
// });

console.log(pipe(g, f)(10));
console.log(compose(g, f)(10));

/**

  • 异步怎么处理呢
  • */
const init = () => Promise.resolve(10);
const a = (content) => {
	return new Promise((resovle, reject) => {
		setTimeout(() => {
			resovle(`${content}NNN`)
		}, 1000)
	})
};

const b = (content) => {
	return new Promise((resovle, reject) => {
		setTimeout(() => {
			resovle(`${content}MMM`)
		}, 1000)
	})
};


const pg = require('promise-generator');
pg([init, a, b]).then((data) => {
	console.log('promise-generator',data);
});


const promiseGenerator = require('./promiseGenerator')
promiseGenerator([init, a, b]).then((res) => {
	console.log(res)
})

/**

  • 到现在 两个函数中有异步的和没有异步的都已经处理OK了 总结一下:顺序处理函数的都可以通过这种方式去实现
    */

async await使用顺序执行 待优化

const asyncRequest = (requestArrs, context, init) => {

	const values = init && [init] || [];

	let num = 0;

	const req = async () => {

		try {
			for (const request of requestArrs) {
				values[num] = await context[request](values.slice(-1)[0] || null);
				num++;
			}
			return values.slice(-1)[0];

		} catch (err) {
			console.error(err);

		}

	};

	return req;

}



const steps = {

	step1(res) {

		return new Promise((resolve, reject) => {

			setTimeout(() => {

				resolve(res + 321);

			}, 1000);

		});

	},

	step2(res) {

		return new Promise((resolve, reject) => {

			setTimeout(() => {

				resolve(123 + res);

			}, 500);

		});

	}

};



asyncRequest(['step1', 'step2'], steps, 444)().then(res => {

	console.log(res);

});

函数式

  • 主要思想是把运算过程尽量写成一系列嵌套的函数调用。
  • 每一步都是单纯的运算,而且都有返回值。
  • 函数式编程强调没有"副作用",意味着函数要保持独立,所有功能就是返回一个新的值,没有其他行为,尤其是不得修改外部变量的值。
  • 当你使用命令式代码把函数和中间变量组合在一起的时候,就如同使用胶带把他们强行粘起来,而函数组合的方式看起来更自然流畅
    备注:函数很单纯,不要存放任何的变量,然后通过compose 或者 pipe 来进行合并一起 本质还是reduce filter
  • 你所有的 function 都应当接收输入并返回输出
  • 另一个是const比较符合函数式编程思想,运算不改变值,只是新建值,而且这样也有利于将来的分布式运算;
  • 高阶函数的定义就是将其他函数看做值的函数。FP 程序员一天到晚都在写这些东西!
@yangchongduo yangchongduo changed the title FP curry anD FP curry && compose Oct 29, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant