使用hof / compose / currying / partial application / monads可以将此代码重构为更具功能性的编程风格吗?

时间:2017-03-07 23:59:40

标签: javascript functional-programming composition currying

我刚刚开始学习函数式编程,并且我正在努力实践我所学到的知识。我已经在下面得到了这段代码,我不知道在哪里可以应用函数组合,在此函数中部分应用。

任何想法如何使用功能技术重构这个?

function compareCodes(validateFn, moreProcessingFn, doStuffOnCodeAFn, doStuffOnCodeBFn, doSomething1Fn, doSomething2Fn, codeA, codeB, param1, param2) {

    let result = null;
    if (validateFn(codeA, codeB)) {
        const isCodeAValid = doStuffOnCodeAFn(codeA);  // returns a boolean
        const isCodeBValid = doStuffOnCodeBFn(codeB);  // returns a boolean
        const isItAMatch = moreProcessingFn(isCodeAValid, isCodeBValid, codeA, codeB); // returns a boolean
        if (isItAMatch) {
            result = doSomething1Fn (param1, param2);
        } else {
            result = doSomething2Fn (param1, param2);
        }
    }
    return result;
}

1 个答案:

答案 0 :(得分:1)

第一步是摆脱所有辅助变量。虽然布尔中间变量易于理解其描述性名称,但至少result是完全没必要的。

function compareCodes(validateFn, moreProcessingFn, doStuffOnCodeAFn, doStuffOnCodeBFn, doSomething1Fn, doSomething2Fn, codeA, codeB, param1, param2) {
    return validateFn(codeA, codeB)
      ? (moreProcessingFn(doStuffOnCodeAFn(codeA), doStuffOnCodeBFn(codeB), codeA, codeB)
          ? doSomething1Fn
          : doSomething2Fn
        )(param1, param2)
      : null;
}

接下来你可以应用一些currying(你可以按参数执行,但我认为它在可能会一起使用的块中更有用):

function compareCodes(validateFn, moreProcessingFn, doStuffOnCodeAFn, doStuffOnCodeBFn, doSomething1Fn, doSomething2Fn) {
    return function(codeA, codeB) {
        return validateFn(codeA, codeB)
          ? moreProcessingFn(doStuffOnCodeAFn(codeA), doStuffOnCodeBFn(codeB), codeA, codeB)
              ? doSomething1Fn
              : doSomething2Fn
          : function(param1, param2) { return null; };
    };
}

但那是关于它的。虽然可以为条件编写自己的组合子并将多个参数并行馈送到多个函数中,但是在这个过程中你不会获得任何东西。肯定没有像组合这样的标准组合器可以帮助你。

如果你不再总是提供两件东西(A和B,1和2),而是作为不同的参数,可能会有所不同。如果您改为修改所有函数来代替元组(这里表示为长度为2的数组,给定JavaScript缺少对类型),我们可以做一些事情。首先我们转换自

function compareCodes(validateFn, moreProcessingFn, [doStuffOnCodeAFn, doStuffOnCodeBFn], [doSomething1Fn, doSomething2Fn], [codeA, codeB], [param1, param2]) {
    return validateFn([codeA, codeB])
      ? (moreProcessingFn([doStuffOnCodeAFn(codeA), doStuffOnCodeBFn(codeB)], [codeA, codeB])
          ? doSomething1Fn
          : doSomething2Fn
        )([param1, param2])
      : null;
}

to(我使用ES6语法,值得注意的箭头函数和解构)

const bimap = ([f, g]) => ([x, y]) => [f(x), g(y)];
const fst = ([x, _]) => x;
const snd = ([_, y]) => y;

function compareCodes(validate, moreProcessing, doStuff, doSomething, code, param) {
    return validate(code)
      ? (moreProcessing(bimap(doStuff)(code), code)
          ? fst
          : snd
        )(doSomething)(param)
      : null;
}

现在我们可以通过组合器解决这个问题:

const compose = f => g => x => f(g(x));
const bind = f => g => x => f(g(x), x);
const cond = pred => then => other => x => pred(x) ? then(x) : other(x);
const k = x => _ => x;


function compareCodes(validate, moreProcessing, doStuff, doSomething)
    return cond(validate,
                cond(bind(moreProcessing)(compose(bimap)(doStuff)),
                    fst(doSomething),
                    snd(doSomething)
                ),
                k(k(null))
           );
}

我们可以进一步明确compareCodes的完全无定义,但说实话,这不值得。

相关问题