Javascript 在Ramda中组合函数,每个函数接收相同的值

Javascript 在Ramda中组合函数,每个函数接收相同的值,javascript,functional-programming,composition,ramda.js,Javascript,Functional Programming,Composition,Ramda.js,如果我想编写一系列函数,我可以使用compose,这将允许我定义一系列函数,将一个或多个参数传递到第一个函数,然后将第一个函数的返回值传递到第二个函数,将第二个函数的返回值传递到第三个函数,依此类推 compose(f3, f2, f1)(value); 这相当于: f3(f2(f1(value))) 但是,如果我希望使用值调用所有三个函数,该怎么办 我的用例是我有一系列的函数来验证一段数据。在每种情况下,如果值有效,则函数要么抛出错误,要么不执行任何操作。我需要以一种方式组合这些验证函数,

如果我想编写一系列函数,我可以使用
compose
,这将允许我定义一系列函数,将一个或多个参数传递到第一个函数,然后将第一个函数的返回值传递到第二个函数,将第二个函数的返回值传递到第三个函数,依此类推

compose(f3, f2, f1)(value);
这相当于:

f3(f2(f1(value)))
但是,如果我希望使用
值调用所有三个函数,该怎么办

我的用例是我有一系列的函数来验证一段数据。在每种情况下,如果值有效,则函数要么抛出错误,要么不执行任何操作。我需要以一种方式组合这些验证函数,即传入一个值将导致每个函数按顺序使用该值调用。实际上:

f1(value);
f2(value);
f3(value);
// Do something now we are sure the value is valid.
使用ramda提供的函数进行此操作的唯一方法是使用逻辑运算符,以防止在值返回false时发生短路:

const f1 = (v) => console.log(`f1 called with '${v}'`);
const f2 = (v) => console.log(`f2 called with '${v}'`);
const f3 = (v) => console.log(`f3 called with '${v}'`);

const callAll = compose(complement, anyPass);
callAll([f1, f2, f3])('x');

然而,这感觉像是误用了
anyPass
。这是实现我想要的最合适的方式吗

有效:
f1(值);f2(值);f3(价值)

每当您在代码中看到分号时,您就知道您不是在功能性编程,而是在执行一个副作用:-)

不要那样做。实际上,最简单的方法是使用
anyPass
,但是让验证函数返回布尔值,而不是抛出异常

如果需要返回错误消息,可以使用
数据类型和:


如果将函数视为单子,则可以合成副作用。下面是一个普通的Javascript草图,但您也可以使用Ramda来表达:

const-chain=f=>g=>x=>f(g(x))(x);
常数=x=>y=>x;
常数id=x=>x;
const yourFun=x=>y=>y;
常数倍=(f,acc)=>xs=>xs.reduce((acc,x)=>f(acc)(x),acc);
常数comp=f=>g=>x=>f(g(x));
常数compn=(…fs)=>倍数(comp,id)(fs);
常量f1=x=>{console.log(`f1用${x}`)调用)
const f2=x=>{console.log(`f2用${x}`)调用)
const f3=x=>{console.log(`f3用${x}`)调用)
康普恩(
链(你的乐趣)(f3),
链(你的乐趣)(f2),
链(你的乐趣)(f1)

)(“x”)通过让验证函数返回布尔值并使用
reduce
,可以使事情变得简单:

// A general purpose, curried validation function
const validate = R.curry((validators, value) =>
  R.reduce((acc, fn) => {
    return acc === false ? acc : fn(value)
  }, true, validators));


const myValidators = [f1, f2, f3]; // Functions return booleans
const myValidator = validate(myValidators);

const isValid = myValidator(myValue); // Returns true or false
工作小提琴

但是,如果我想用值调用所有三个函数,该怎么办

调用在一个值上运行多个函数的函数

第二个参数是函数数组。值(在本例中为“x”)按顺序抛出到每个值中

但是,在这之后,R.converge接受f1、f2、f3的返回值,并将它们作为第一个参数的参数输入。您不需要R.converge的这一部分,因为您没有对返回值做任何操作,所以您可以只使用一个不做任何操作的函数

因此,callAll可以写成:

const callAll =
  R.converge(() => {});
其执行方式如下:

callAll([f1, f2, f3])('x');
或未结婚:

const callAll =
  R.uncurryN(2, R.converge(() => {}));

callAll([f1, f2, f3], 'x');

您从哪里获得
other
呢?@adrice727:许多提供了
other
实现。您可以稍微简化
以减少((acc,fn)=>acc&&fn(value),true,validator)
。对这种通用方法的一个(可能相对较小)反对意见是,它要求您运行每个验证,即使第一个验证返回
false
。短路可能是可取的。请参阅Bergi的建议以了解替代方案。
callAll([f1, f2, f3])('x');
const callAll =
  R.uncurryN(2, R.converge(() => {}));

callAll([f1, f2, f3], 'x');