Curry /管道功能

时间:2018-10-10 03:53:32

标签: javascript node.js currying ramda.js

我目前正在使用Ramda library来构造新功能。 这是我的代码段

function auth(operand) {
  if (operand.prevResult.pass && operand.req.authenticated) {
    return operand;
  } else {
    operand.prevResult.pass = false;
    return operand;
  }
}

function validate(operand) {
  if (operand.prevResult.pass && operand.req.validated) {
    return operand;
  } else {
    operand.prevResult.pass = false;
    return operand;
  }
}

function postHandle(operand) {
  if (operand.prevResult.pass){
    operand.res.send();
  } else {
    console.log('some error occured')
  }

}

const doPost = R.pipe(auth, validate, postHandle);
//const doGet = R.pipe(auth, validate, getHandle);
//const doPatch ...etc

const req = {authenticated: true, validated: true};
const res = {send: () => {console.log('sent')}};
doPost({req, res, prevResult: {pass: true}});

目标是能够使用某些共享方法(例如身份验证/验证)来创建doPostdoGetdoPatch等。

但是,我能找到的最佳功能是Ramda中的R.pipe。这样做

(((a, b, …, n) → o), (o → p), …, (x → y), (y → z)) → ((a, b, …, n) → z)

它只允许我在构造函数中传递一个参数(例如doPost,doGet)。因此,最后一行doPost({req, res, prevResult: {pass: true}});

我希望有一种方法可以传递三个参数。所以我最后可以做doPost(req, res, {pass: true})。而且每个函数签名看起来也会更好,例如function auth(req, res, prevResult)function validate(req, res, prevResult)function postHandle(req, res, prevResult)

2 个答案:

答案 0 :(得分:0)

R.pipe:除第一个函数外的所有函数将仅接受一个参数。

我们可以通过使用咖喱函数R.curry来克服这一问题。

通常,咖喱函数将返回一个函数,直到获得函数签名中提到的所有参数为止。

创建auth,validate和postHandle的咖喱版本,如下所述。 我希望这能解决您的问题。

const R = require('ramda');

const isPrevResultPass = R.propEq('pass', true);
const isAuthenticated = R.propEq('authenticated', true);
const isValidated = R.propEq('validated', true);
const updatePrevResultPass = R.assoc('pass');

const auth = R.curry((req, res, prevResult) => {
    if (isPrevResultPass(prevResult) && isAuthenticated(req))
        return prevResult;
    return updatePrevResultPass(false, prevResult)
});

const validate = R.curry((req, res, prevResult) => {
    if (isPrevResultPass(prevResult) && isValidated(req))
        return prevResult;
    return updatePrevResultPass(false, prevResult);
});

const postHandle = R.curry((req, res, prevResult) => {
    if (R.not(isPrevResultPass(prevResult)))
        console.log('some error occured')
    res.send();
});


const req = {authenticated: true, validated: true};
const res = {send: () => {console.log('sent')}};
const prevResult = { pass: true };

const doPost = R.pipe(auth(req, res), validate(req, res), postHandle(req, res));
doPost(prevResult);

答案 1 :(得分:0)

如果要通过函数的组成传递多个值,则需要能够从各个函数返回多个值。

实现此目标的一种方法是使用一个像您一样的对象(尽管回荡Shyam的注释以分解参数以提高可读性)。

在一系列组合函数中的函数之间传递多个值的另一种方法是通过连续传递样式,其中提供的回调有望接收多个结果。

const multiPipe = (...fns) => fns.reduceRight(
    (pipe, next) => (...args) => next(...args)(pipe))

const fn = multiPipe(
  (a, b) => k => k(a * 2, b * 3),
  (a, b) => k => k(a - 5, b - 2)
)

fn(1, 2)((a, b) => console.log(a, b))

从延续传递样式中获得的一个有趣的功能是,您还可以短路管道,以通过不返回提供的延续而返回结果来防止调用其余函数。

const multiPipe = (...fns) => fns.reduceRight(
    (pipe, next) => (...args) => next(...args)(pipe))

const auth = (req, res) => next =>
  req.authenticated
    ? next(req, res)
    : console.log('authentication failed')

const validate = (req, res) => next =>
  req.validated
    ? next(req, res)
    : console.log('validation failed')

const postHandle = (req, res) => next =>
  res.send()

const doPost = (req, res) =>
  multiPipe(auth, validate, postHandle)(req, res)()

const req = { authenticated: true, validated: true }
const res = { send: () => console.log('sent') }

doPost(req, res)