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

问题描述 投票:2回答:4

如果我想编写一系列函数,我可以使用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的误用。这是实现我想要的最合适的方式吗?

javascript functional-programming composition ramda.js
4个回答
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


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")

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如何用于组合带效果的计算。


1
投票

通过让验证函数返回布尔值并使用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

工作小提琴here

© www.soinside.com 2019 - 2024. All rights reserved.