在Ramda中编写函数,每个函数接收相同的值

时间:2017-11-30 11:48:57

标签: javascript functional-programming composition ramda.js

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

compose(f3, f2, f1)(value);

相当于:

f3(f2(f1(value)))

但是,如果我想用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');

REPL

然而,这感觉就像滥用anyPass一样。这是实现我想要的最合适的方式吗?

4 个答案:

答案 0 :(得分:3)

  

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

一个值上运行多个函数的函数称为R.converge

R.converge(
  () => {},
  [f1, f2, f3],
)('x');

第二个参数是一个函数数组。价值(在这种情况下' 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');

Run with REPL

答案 1 :(得分:2)

  

有效地:f1(value); f2(value); f3(value);

每当你在代码中看到一个分号时,你知道你没有在功能上进行编程但是正在执行副作用: - )

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

如果您需要收回错误消息,请使用Either数据类型和traverse

const f1 = (v) => true ? Either.right("it's fine") : Either.left("oops");
const f2 = (v) => false? Either.right("it's fine") : Either.left("oops");
const f3 = (v) => true ? Either.right("it's fine") : Either.left("oops");

traverse(Either.of, R.apply('x'), [f1, f2, f3]); // Left("oops")

答案 2 :(得分:1)

如果将函数视为monad,则可以编写副作用。这是一个香草Javascript草图,但你也可以用Ramda表达它:



const chain = f => g => x => f(g(x)) (x);
const of = x => y => x;


const id = x => x;
const yourFun = x => y => y;


const fold = (f, acc) => xs => xs.reduce((acc_, x) => f(acc_) (x), acc);


const comp = f => g => x => f(g(x));
const compn = (...fs) => fold(comp, id) (fs);


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


compn(
  chain(yourFun) (f3),
  chain(yourFun) (f2),
  chain(yourFun) (f1)
) ("x");




现在yourFun忽略了第一个参数。您可能希望将其替换为对您的案例更有用的内容。

请注意,这不仅仅是一种教育活动,也不是一种正确的方法。我想告诉你monad如何用于组合带效果的计算。

答案 3 :(得分:1)

通过让验证函数返回布尔值并使用@ Service public class Class1 { /% Method 1 %/ /% Method 2 %/ /% Method 3 %/ /% Method 4 %/ }

,您可以保持简单
public class Class2
{
    @ Autowired
    private Class1 class1;
    /% class1.Method1() %/
    /% class1.Method1() %/
    .
    .
    .
}

工作小提琴here