在使用高阶函数时,我遇到了一个问题。假设我有以下不使用它们的代码(而是调用全局函数):
import {db_insert} from 'some-db-lib' // function with side-effect
const save_item = (item) => {
// some logic like validating item data...
db_insert(item) // call db_insert globally
}
const handle_request = (request) => {
// some logic like sanitizing request...
save_item(request.data) // call save_item globally
}
handle_request(some_request)现在,同样的例子,通过使用高阶函数(将副作用作为函数参数注入):
import {db_insert} from 'some-db-lib' // function with side-effect
const save_item = (item, insert) => { // inject insert
// some logic like validating item data...
insert(item)
}
const handle_request = (request, save, insert) => { // inject save and insert
// some logic like sanitizing request...
save(request.data, insert)
}
handle_request(some_request, save_item, db_insert)想象一下,在一个更大的函数树中互相调用。最后一个例子会变成一大堆相互传递函数的函数。
这是隔离副作用的正确方法吗?我是不是遗漏了什么?
发布于 2017-02-12 04:49:23
高阶函数
高阶函数用于从函数应用中抽象出来。公共HOF至少接受一个函数f和至少一个附加参数x,并将f应用于x。下面是最简单的例子:
const apply = (f, x) => f(x);不是特别有趣。关键的一点是,每个有意义的HOF都会做一些额外的事情。例如,它迭代地应用于给定函数(map,reduce)。它由两个函数组成:
const comp = (f, g) => x => f(g(x));
const inc = x => x + 1;
console.log(
comp(inc, inc) (0) // 2
);
它将一个函数应用于Object,即使此函数只接受Numbers:
const destruct = (x, y, f) => ({[x]:a, [y]:b}) => f(a, b);
const add = (x, y) => x + y;
const o = {propA:2, propB:3};
console.log(
destruct("propA", "propB", add) (o) // 5
);
或者它部分应用了一个函数:
const partial = (f, ...args) => (...args2) => f(...args, ...args2);
sum5 = (v, w, x, y, z) => v + w + x + y + z;
subtotal = partial(sum5, 1, 2, 3);
console.log(
subtotal(4, 5) // 15
);
延续传球风格
你的代码模式_a = (x, b, c) => b(x, c)实际上是来自延续传递风格。它是高阶函数的一种特殊形式,其中一个函数的最后一个参数必须始终是另一个函数,该函数表示连续,即当前计算的其余部分。延续函数不是由其周围函数的参数提供的,而是由它的计算结果提供的。延续函数,或者更确切地说,它的应用是所谓的return语句的替换。
虽然你会在函数式Javascript中一直遇到HOFs,但延续传递风格是相当罕见的。当您查看以下示例时,您将知道原因:
const eqk = (x,y,k) => k(y === x);
const mulk = (x,y,k) => k(y * x);
const subk = (x,y,k) => k(y - x);
const powerk = (x, y, k) =>
eqk(0, y, isDone =>
isDone
? k(1)
: subk(1, y, _y=>
powerk(x, _y, res =>
mulk(x, res, k))));
powerk(2, 8, x => {console.log("powerk:", x); return x});
控制反转
在函数式编程中,您可以通过应用纯(高阶)函数来实现控制反转。纯函数仅根据其输入产生一个值。没有副作用。调用这种纯函数的调用者可以将生成的值用于进一步处理,也可以将其丢弃。调用者决定所产生的值如何与程序交互。因此,控件从被调用者反转到调用者。
除此之外,调用者可以使用被调用者的参数将纯函数传递给被调用者。换句话说,调用者可以在被调用者中注入惰性表达式。因此,调用者不仅控制被调用者执行的计算的结果,而且还能够影响该计算本身。
依赖注入
在函数式编程中不需要特定的依赖注入,因为范型控制的内在反转。函数之间的全局依赖是完全没有问题的,只要所有涉及的函数都是纯函数,因此不会修改全局状态。
https://stackoverflow.com/questions/42179513
复制相似问题