簡體   English   中英

撰寫-函數式編程

[英]Compose - functional programming

我想創建自己的compose實現

這有效

const compose = (...fns) => fns.reduce((f,g) => (...args) => f(g(...args)));

這不是

const compose1 = (...fns) => (...args) => fns.reduce((f,g) => f(g(...args)));

const multi = a => x => x*a;
const devide = a => x => x/a;
const add = a => x => x+a;

compose(add(6), multi(4), devide(5))(5); // 10 as expected

compose1(add(6), multi(4), devide(5))(5); // Uncaught TypeError: f is not a function

您能解釋一下為什么第二種實現無效嗎?

這是使版本正常工作所需的操作:

const compose1 = (...fns) => (...args) => fns.reduceRight((res, f) => f(res), fns.pop()(...args))

您失敗的原因是因為reduce (和reduceRight )采用了具有此簽名的功能:

(previousValue, currentValue) => newPreviousValue

說明:

在您的版本中發生的是,第一次,reduce調用您的函數之后, newPreviousValue現在不再是一個函數,現在是f(g(...args)) (最后一個函數調用的結果),所以當reduce嘗試再次“調用”該函數,它使用上次調用的結果就好像它是一個函數一樣,因此會出現錯誤。

如果您看到上面的內容,則respreviousValue ,它是最后一個函數調用的結果,但未用作函數。

進一步

如果您想知道第一次調用如何成功,那么原因是因為您沒有提供reduce的初始值,所以它只是將列表中的前兩個函數作為函數的參數,允許您這樣做: f(g(...args))

const compose = (...fns) => {
  console.log('function', fns);
  return fns.reduce((f,g) => {
    console.log('f and g' , f,g)
    return (...args) => {
      console.log('args is ' , args)
      return f(g(...args));
    }
  })
};

// call with 
compose(add(6), multi(4), devide(5))(5);

將產生

VM1239:2 function (3) [ƒ, ƒ, ƒ]
VM1239:4 f and g x => x+a x => x*a
VM1239:4 f and g (...args) => {
      console.log('args is ' , args)
      return f(g(...args));
    } x => x/a
VM1239:6 args is  [5]
VM1239:6 args is  [1]
10

哪個工作都很好,對您的compose1做同樣的compose1

const compose1 = (...fns) => {
  console.log('functions ', fns)
  return (...args) => {
    console.log('args', args)
    return fns.reduce((f,g) => {
      console.log('f and g', f,g)
      return f(g(...args))
    })
  }
};
//called with 
compose1(add(6), multi(4), devide(5))(5)

將產生

VM1783:2 functions  (3) [ƒ, ƒ, ƒ]
 0: x => x+a
 1: x => x*a
 2: x => x/a
VM1783:4 args [5]
VM1783:6 f and g x => x+a x => x*a
VM1783:6 f and g 26 x => x/a
VM1783:7 Uncaught TypeError: f is not a function
    at fns.reduce (<anonymous>:7:14)
    at Array.reduce (<anonymous>)
    at args (<anonymous>:5:16)
    at <anonymous>:1:38

所以你的f現在是26這不是一個函數:)

說明:

you called 
f (g (...args)) 
f ( g ( 5 ) )
f ( 5 * a)  // a is 4
f ( 20 )
16 + a //  a is 6
26

通過將語法擴展為多行,您可以開始查看第二個函數中的問題所在。 您正在調用fns.reduce ,而您應該在其中調用args.reduce 從那里開始,它仍然返回一個不同的值,因此很可能還會發生其他一些問題,但這只是一個開始。

第二個控制台日志還應顯示f的值不是您期望的值。

理想情況下,您只應為非常簡單的操作或為您已經以易於閱讀和測試的方式進行了全面測試的東西寫速記。

 const compose = (...fns) => { return fns.reduce((f,g) => { console.log('f: ',f,'g: ',g) return (...args) => f(g(...args)) }) }; const compose1 = (...fns) => { return (...args) => { return args.reduce((f,g) => { //was fns.reduce console.log('f: ',f,'g: ',g) return f(g(...args)) }) } } const multi = a => x => x*a; const devide = a => x => x/a; const add = a => x => x+a; var result1 = compose(add(6), multi(4), devide(5))(5); // 10 as expected console.log(result1) var result2 = compose1(add(6), multi(4), devide(5))(5); // Uncaught TypeError: f is not a function console.log(result2) 

讓我們通過分解來看看您的compose1

const compose1 = (...fns) => {
    // Returns a function that reduces fns each time it is called        
    return (...args) => {
        // Returns the reduction of fns
        return fns.reduce((f,g) => {
            // Returns the result of calling f(g(...args))
            return f(g(...args))
        })
    }
};

現在讓我們來看一下這個版本的compose的示例調用:

compose1(add(6), multi(4), devide(5))(5);

首先,我們稱為compose1 這將返回此函數:

(...args) => {
    // Returns the reduction of fns
    return fns.reduce((f,g) => {
        // Returns the result of calling f(g(...args))
        return f(g(...args))
    })
}

然后,我們使用參數5調用此函數,該參數實際上是像先前返回的函數一樣調用fns.reduce 要查看到底出了什么問題,讓我們來看一看reduce的一些迭代:

第一次迭代:

fns.reduce((f = add(6), g = multi(4)) => {
    // Returns the result of calling f(g(...args))
    return f(g(...args = [5]))
    // g is `multi(4)`, so do `multi(4)(5)`, which returns 20. Next:
    // f is `add(6)`, so do `add(6)(20)`, which returns 26.
    // Remember that the return from last iteration is
    //   the first parameter of the next iteration
})

第二次迭代:

fns.reduce((f = 26, g = devide(5)) => {
    // Returns the result of calling f(g(...args))
    return f(g(...args = [5]))
    // g is `devide(5)`, so do `devide(5)(5)`, which returns 1. Next:
    // f is 26, so do `26(1)`. However, 26 is not a function.
    // You get the error `f is not a function`.
})

暫無
暫無

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

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