2017-03-07 47 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

相關問題