2017-03-07 44 views
0

我刚刚开始学习函数式编程,并试图将我学到的东西付诸实践。我有下面的代码,我只是不知道在哪里可以应用函数组合,部分应用在这个函数中。可以使用hof/compose/currying/partial application/monads将此代码重构为更多功能的编程风格吗?

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

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; 
} 
+0

我投票结束题目,因为这属于codereview.stackexchange.com – Paul

+0

@Paul Code Review不会检查涉及'doSomething'占位符的问题。此外,即使它是代码审查的专题问题,“属于某个其他网站_”[也不构成有效的关闭原因](http://meta.stackexchange.com/q/260769/148099)。 –

+1

为什么要将嵌套条件放在函数中呢?具有三个以上参数的高阶函数可以定期重构。 – ftor

回答

2

第一步是摆脱所有的帮助变量。尽管布尔中间变量容易理解他们的描述性名称,但至少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; 
} 

接下来,您可以申请一些钻营(你可以做到这一点每个参数,但我认为这是比较有用的,这将有可能被同时使用的块):

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

到(我使用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的完全无点定义,但说实话,这不值得。

+0

真的很感谢@Bergi的回答。这对让我思考功能真的很有帮助。 – Darwin

+0

我希望你不介意问我关于辅助变量的进一步问题。 如果你有一个辅助变量并且这个辅助变量在函数中被多次使用会怎样? 假设我有这个: 'function matchCode(codeA,codeB){ let let hashMapData = createMap(); //昂贵的操作 const arrA = createArrayFromCode(codeA,hashMapData); const arrB = createArrayFromCode(codeB,hashMapData); return(arrA.length> 0 && arrB.length> 0)?compareArray(arrA,arrB):true; }' 你将如何去重构这种情况? – Darwin

+0

@Bergi不错的'bind'用法# – ftor

相关问题