簡體   English   中英

Underscore.js函數式編程是假的嗎?

[英]Is Underscore.js functional programming a fake?

根據我對函數式編程的理解,您應該能夠鏈接多個函數,然后通過遍歷一次輸入數據來執行整個鏈。

換句話說,當我執行以下操作(偽代碼)時:

list = [1, 2, 3];
sum_squares = list
   .map(function(item) { return item * item; })
   .reduce(function(total, item) { return total + item; }, 0);

我希望列表將遍歷一次 ,每個值將被平方,然后將所有內容相加(因此,reduce操作將根據需要調用map操作)。

但是,當我查看Underscore.js的源代碼時,我發現所有“函數式編程”功能實際上都產生中間集合,例如,這樣:

// Return the results of applying the iteratee to each element.
_.map = _.collect = function(obj, iteratee, context) {
  iteratee = cb(iteratee, context);
  var keys = !isArrayLike(obj) && _.keys(obj),
      length = (keys || obj).length,
      results = Array(length);
  for (var index = 0; index < length; index++) {
    var currentKey = keys ? keys[index] : index;
    results[index] = iteratee(obj[currentKey], currentKey, obj);
  }
  return results;
};

因此,問題是,正如標題中所述,我們是否在自欺欺人地認為使用Underscore.js進行函數式編程?

我們實際上所做的是使程序看起來像函數式編程,而實際上卻不是函數式編程。 想象一下,我在長度為N的列表上構建了一個由K filter()函數組成的長鏈,然后在Underscore.js中,我的計算復雜度將是O(K * N),而不是函數編程中所期望的O(N)。

PS:我聽說過很多關於JavaScript的函數式編程的知識,並且希望看到一些函數,生成器,綁定...我缺少什么嗎?

Underscore.js函數式編程是假的嗎?

不,Underscore確實具有許多有用的功能助手功能。 但是,是的, 他們做錯了 您可能想看看Ramda

我希望清單會被遍歷一次

是的, list只會被遍歷一次。 它不會被突變,也不會保存在內存中(如果您沒有變量引用的話)。 reduce遍歷是一個不同的列表,由map產生。

所有功能實際上產生中間集合

是的,這是用JavaScript之類的語言實現此功能的最簡單方法。 許多人都依賴map在調用reduce之前執行其所有回調,因為它們使用了副作用。 JS不會強制執行純函數,並且庫作者也不想使人們感到困惑。

請注意,即使在像Haskell這樣的純語言中,也會構建中間結構1 ,盡管它會被懶惰地使用,所以它永遠不會被整體分配。

有一些庫使用Clojure已知的換能器概念,以嚴格的語言來實現這種優化。 JS中的示例是transduceconverters-jsconverters.jsunderarm Underscore和Ramda也一直在調查他們2

我期待看到一些[…]發電機

是的,可以延遲使用的生成器/迭代器是另一種選擇。 您需要看一下Lazy.jshighlandimmutable-js

[1]:嗯, 不是真的 -這太簡單了
[2]: https : //github.com/jashkenas/underscore/issues/1896,https : //github.com/ramda/ramda/pull/865

函數式編程與遍歷一次序列無關。 如果要求Haskell filter pred (map fx) ,那么即使是純粹的Haskell也將遍歷嚴格列表的長度兩次。

函數式編程是一種更簡單的計算模型,其中僅允許發生的事情不包括副作用。 例如,在Haskell中,基本上只允許發生以下情況:

  1. 您可以將值f應用於另一個值x ,從而產生沒有副作用的新值fx 第一值f被稱為“函數”。 一定是在任何時候將相同的f應用於相同的x都會得到fx的相同答案。
  2. 您可以給值命名,該值可以是函數,簡單值或其他任何值。
  3. 您可以使用新的類型簽名為數據定義新的結構,和/或使用這些“構造函數”對某些數據進行結構化。
  4. 您可以定義一個新的類型類,或顯示現有數據結構如何實例化一個類型類。
  5. 您可以“匹配模式”數據結構,這是案例分派與為項目其余部分命名數據結構各部分的組合。

請注意,在Haskell中“打印某些內容到控制台”是怎么做的,“更改現有數據結構”也是如此。 要將一個內容打印到控制台,您可以構造一個值,該值代表將內容打印到控制台的操作,然后為其指定一個特殊的名稱main (在編譯Haskell時,您將計算名為main的操作,然后將其作為可執行程序寫入磁盤;在運行該程序時,該操作實際上已完成。)如果已經有一個main ,則可以找出哪里您想要將新操作包括在該程序的現有操作中,然后使用一個函數將控制台日志與現有操作進行排序。 Haskell程序從不執行任何操作。 它只是代表在做某事。

那就是函數式編程的本質。 它比普通的編程語言要弱,在普通的編程語言中,語言本身就可以完成工作,例如JavaScript的console.log()函數,只要JS解釋器運行它,它就會立即產生副作用。 特別是,在正常程序中,有些東西是(或似乎是)O(1)或O(log(log(n()))),而我們最好的功能等效項是O(log(n))。

暫無
暫無

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

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