Карри / Пайпинг функция - PullRequest
       31

Карри / Пайпинг функция

0 голосов
/ 10 октября 2018

В настоящее время я использую библиотеку Ramda для создания новых функций.Вот фрагмент моего кода

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}});

Цель состояла в том, чтобы иметь возможность создавать doPost, doGet, doPatch etcs, используя некоторые общие методы, такие как аутентификация / валидация.

Однако лучшая функция, которую я могу найти, это R.pipe в Ramda.Это делает это

(((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 голосов
/ 10 октября 2018

Если вы хотите передать несколько значений через композицию функций, вам нужна возможность вернуть несколько значений из отдельных функций.

Один из способов добиться этого - использовать объект, подобный вашему (хотя эхоКомментарий Шьяма о деструктурировании аргументов для обеспечения удобочитаемости).

Еще один способ передачи нескольких значений между функциями в серии составных функций - это стиль передачи продолжения, где ожидаемый обратный вызов должен получить несколько результатов.

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)
0 голосов
/ 10 октября 2018

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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...