簡體   English   中英

在函數式編程方法中創建撰寫函數

[英]create compose function in functional programming approach

我試圖通過重新創建撰寫來了解撰寫的工作方式。 作為其一部分,我創建了一個簡單的計算器來獲取一個值,並根據該值獲得回報。

https://medium.com/javascript-scene/reduce-composing-software-fe22f0c39a1d#.rxqm3dqje

本質上最終的目標是創建一個可以在下面完成的功能。 https://github.com/ngrx/example-app/blob/master/src/app/reducers/index.ts#L150

很高興:能夠傳遞多個存款值,並且可以隨時間計算復利。

最好有一些評論,以便我了解函數式編程方法的狀況。

(()=>{
    // Generic compose function to handle anything
    const compose = (...fns) => (x) => {
        return fns.reduceRight((acc,fn)=>{
            return fn(acc);
        }, x)
    };

    const getInterest = (value) => {
        if (value < 1000) {
            return 1 / 100
        }

        if (value < 10000) {
            return 2 / 100
        }

        return 3 / 100;
    };

    const getDeposit = (value) => {
        return value;
    };

    const calculator = compose(getDeposit, getInterest)

    console.log(calculator(1000)) // Should return value of 1000 * interest rate. I currently get 0.03
})();

問題是您永遠不要將兩個值相乘: valueinterest

因此,您應該將另一個函數傳遞給合成,該函數將乘以之前的兩個結果。

這意味着該函數將需要獲取2個參數,而其他兩個僅接受一個。 通常,一個函數可能需要任何數量的參數。 因此,作曲家應該能夠將足夠的參數傳遞給每個函數。 此外,函數還可能以數組的形式返回多個值。 這些值應可作為鏈中下一個函數的參數使用,同時還要保留所有先前返回的值。

另一件事是,盡管您已實現compose從右到左執行功能,但是傳遞的函數順序似乎暗示您希望它們從左到右執行,先是getDeposit然后是getInterest ,即使在您這種情況下,雙向工作。 不過,我還是建議換個位置。

因此,您可以通過以下方法來完成所有工作:

 (()=>{ // Generic compose function to handle anything const compose = (...fns) => (...args) => { return fns.reduceRight((acc,fn)=>{ // Call the function with all values we have gathered so far let ret = fn.apply(null, acc); // If function returns a non-array, turn it into an array with one value if (!Array.isArray(ret)) ret = [ret]; // Queue the returned value(s) back into the accumulator, so they can // serve as arguments for the next function call acc.unshift(...ret); return acc; }, args)[0]; // only return the last inserted value }; const getInterest = (value) => { return value < 1000 ? 0.01 : value < 10000 ? 0.02 : 0.03; }; const multiply = (a, b) => a * b; const getDeposit = (value) => value; // Be aware the the rightmost function is executed first: const calculator = compose(multiply, getInterest, getDeposit); console.log(calculator(1000)) // Returns 20, which is 0.02 * 1000 })(); 

備選方案:傳遞對象

上面的實現不是純粹的compose實現,因為它不僅將先前的函數結果傳遞給下一個函數,而且還將所有先前的函數結果傳遞給下一個。 這是不擾民,並打開門更復雜的功能,但如果你想更堅持原來的想法撰寫 ,你必須解決的一個問題:

由於您希望鏈中有一個返回費率的函數,因此鏈中的下一個函數將獲取費率-別無其他。 僅憑一條信息,當然不可能計算結果,結果也需要該值作為輸入。

您可以通過讓getInterest返回一個對象來“解決”此問題,該對象不僅具有速率,而且還具有傳遞給它的值。 您也可以使用數組來實現。

這是一個對象實現:

 (()=>{ // Straightforward implementation: const compose = (...fns) => (...args) => { return fns.reduceRight((acc,fn)=>{ return fn(acc); }, args); }; // Return an object with two properties: value & interest const getInterest = (value) => ({ value, interest: value < 1000 ? 0.01 : value < 10000 ? 0.02 : 0.03 }); // Expect an object as argument, with two properties: const getInterestAmount = ({value, interest}) => value * interest; const getDeposit = (value) => value; // Be aware the the rightmost function is executed first: const calculator = compose(getInterestAmount, getInterest, getDeposit); console.log(calculator(1000)) // Returns 20, which is 0.02 * 1000 })(); 

使用這種方法,您可以傳遞具有更多屬性的對象,因此一切皆有可能。

我實際上很喜歡您的簡單compose函數(僅適用於一元函數),並且我認為您也可以通過以下更改使其暫時起作用:

  • getInterest重命名為...Rate ,因為它返回一個值的乘數。
  • 添加一個新的getInterest函數,該函數采用“ rate getter”和“ value”(采用咖喱形式): getRate => x => getRate(x) * x
  • compose交換計算器參數的順序

    我認為compose通常從右到左( f => g => x => f(g(x)) )起作用, pipe從左到右( f => g => x => g(f(x))

 (()=>{ // Generic compose function to handle anything const compose = (...fns) => (x) => { return fns.reduceRight((acc,fn)=>{ return fn(acc); }, x) }; const defaultRate = (value) => { if (value < 1000) { return 1 / 100 } if (value < 10000) { return 2 / 100 } return 3 / 100; }; const getInterest = getRate => x => getRate(x) * x; const getDeposit = x => 1000; const calculator = compose(getInterest(defaultRate), getDeposit); console.log(calculator()); })(); 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM