自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

函數(shù)式思維:為什么函數(shù)式編程越來(lái)越受關(guān)注

開(kāi)發(fā) 項(xiàng)目管理
函數(shù)式語(yǔ)言不僅在 JVM 上剛剛嶄露頭腳(其中兩個(gè)最有趣的新語(yǔ)言是 Scala 和 Clojure),在 .NET 平臺(tái)上也是才開(kāi)始得到應(yīng)用,在 .NET 平臺(tái)上,F(xiàn)# 是頭等公民。為什么所有平臺(tái)都如此歡迎函數(shù)式編程?答案是,隨著時(shí)間的推移,隨著運(yùn)行時(shí)都要能夠處理更多的繁忙工作,開(kāi)發(fā)人員已經(jīng)能夠?qū)⑷粘H蝿?wù)的更多控制權(quán)割讓給它們。

到目前為止,在本系列的每期文章中,我都說(shuō)明了為什么理解函數(shù)式編程非常重要。但是,有些原因是在多期文章中進(jìn)行說(shuō)明的,只有在綜合思路的更大背景中,才可以完全了解這些原因。在本期文章中,我會(huì)探討函數(shù)式編程方興未艾的所有原因,并綜合前幾期文章中的一些個(gè)人經(jīng)驗(yàn)教訓(xùn)。

在計(jì)算機(jī)科學(xué)短短的發(fā)展歷史中,技術(shù)的主流有時(shí)會(huì)產(chǎn)生分支,包括實(shí)用分支和學(xué)術(shù)分支。20 世紀(jì) 90 年代的 4GL(第四代語(yǔ)言)是一個(gè)實(shí)用分支,而函數(shù)式編程是來(lái)自學(xué)術(shù)界的一個(gè)示例。每隔一段時(shí)間,都會(huì)有一些分支加入主流,函數(shù)式編程目前也是這種情況。函數(shù)式語(yǔ)言不僅在 JVM 上剛剛嶄露頭腳(其中兩個(gè)最有趣的新語(yǔ)言是 Scala 和 Clojure),在 .NET 平臺(tái)上也是才開(kāi)始得到應(yīng)用,在 .NET 平臺(tái)上,F(xiàn)# 是頭等公民。為什么所有平臺(tái)都如此歡迎函數(shù)式編程?答案是,隨著時(shí)間的推移,隨著運(yùn)行時(shí)都要能夠處理更多的繁忙工作,開(kāi)發(fā)人員已經(jīng)能夠?qū)⑷粘H蝿?wù)的更多控制權(quán)割讓給它們。

割讓控制權(quán)

在 20 世紀(jì) 80 年代初,在我上大學(xué)的時(shí)候,我們使用一個(gè)被稱(chēng)為 Pecan Pascal 的開(kāi)發(fā)環(huán)境。其獨(dú)特的特性是,相同的 Pascal 代碼可以在 Apple II 或 IBM PC 上運(yùn)行。Pecan 工程師使用某個(gè)稱(chēng)為 “字節(jié)碼” 的神秘東西實(shí)現(xiàn)了這一壯舉。開(kāi)發(fā)人員將 Pascal 代碼編譯為 “字節(jié)碼”,它可以在每個(gè)平臺(tái)本地編寫(xiě)的 “虛擬機(jī)” 上運(yùn)行。這是一個(gè)可怕的體驗(yàn)!所生成的代碼慢得讓人痛苦,甚至簡(jiǎn)單的類(lèi)賦值也非常緩慢。當(dāng)時(shí)的硬件還沒(méi)有準(zhǔn)備好迎接這個(gè)挑戰(zhàn)。

在發(fā)布 Pecan Pascal 之后的十年,Sun 發(fā)布了 Java,Java 使用了相同的架構(gòu),對(duì)于 20 世紀(jì) 90 年代中期的硬件環(huán)境,運(yùn)行該代碼顯得有些緊張,但最終取得了成功。Java 還增加了其他開(kāi)發(fā)人員友好的特性,如自動(dòng)垃圾收集。使用過(guò)像 C++ 這樣的語(yǔ)言之后,我再也不想在沒(méi)有垃圾收集的語(yǔ)言中編寫(xiě)代碼。我寧愿花將時(shí)間花在更高層次上的抽象上,思考解決復(fù)雜業(yè)務(wù)問(wèn)題的方法,也不愿意在內(nèi)存管理等復(fù)雜的管道問(wèn)題上浪費(fèi)時(shí)間。

Java 緩解了我們與內(nèi)存管理的交互;函數(shù)式編程語(yǔ)言使我們能夠用高層次的抽象取代其他核心構(gòu)建塊,并更注重結(jié)果而不是步驟。

結(jié)果比步驟更重要

函數(shù)式編程的特點(diǎn)之一是存在強(qiáng)大的抽象,它隱藏了許多日常操作的細(xì)節(jié)(比如迭代)。我在本系列文章中一直使用的一個(gè)示例是數(shù)字分類(lèi):確定某個(gè)數(shù)字是 perfectabundant 還是 deficient。清單 1 中顯示的 Java 實(shí)現(xiàn)可以解決這個(gè)問(wèn)題:

清單 1. 自帶緩存總數(shù)的 Java 數(shù)字分類(lèi)器

  1. import static java.lang.Math.sqrt;  
  2.    
  3. public class ImpNumberClassifier {  
  4.     private Set<Integer> _factors;  
  5.     private int _number;  
  6.     private int _sum;  
  7.    
  8.     public ImpNumberClassifier(int number) {  
  9.         _number = number;  
  10.         _factors = new HashSet<Integer>();  
  11.         _factors.add(1);  
  12.         _factors.add(_number);  
  13.         _sum = 0;  
  14.     }  
  15.    
  16.     private boolean isFactor(int factor) {  
  17.         return _number % factor == 0;  
  18.     }  
  19.    
  20.     private void calculateFactors() {  
  21.         for (int i = 1; i <= sqrt(_number) + 1; i++)  
  22.             if (isFactor(i))  
  23.                 addFactor(i);  
  24.     }  
  25.    
  26.     private void addFactor(int factor) {  
  27.         _factors.add(factor);  
  28.         _factors.add(_number / factor);  
  29.     }  
  30.    
  31.     private void sumFactors() {  
  32.         calculateFactors();  
  33.         for (int i : _factors)  
  34.             _sum += i;  
  35.     }  
  36.    
  37.     private int getSum() {  
  38.         if (_sum == 0)  
  39.             sumFactors();  
  40.         return _sum;  
  41.     }  
  42.    
  43.     public boolean isPerfect() {  
  44.         return getSum() - _number == _number;  
  45.     }  
  46.    
  47.     public boolean isAbundant() {  
  48.         return getSum() - _number > _number;  
  49.     }  
  50.    
  51.     public boolean isDeficient() {  
  52.         return getSum() - _number < _number;  
  53.     }  

清單 1 中的代碼是典型的 Java 代碼,它使用迭代來(lái)確定和匯總系數(shù)。在使用函數(shù)式編程語(yǔ)言時(shí),開(kāi)發(fā)人員很少關(guān)心細(xì)節(jié)(比如迭代,由 calculateFactors() 使用)和轉(zhuǎn)換(比如匯總一個(gè)列表,該列表由 sumFactors() 使用),寧愿將這些細(xì)節(jié)留給高階函數(shù)和粗粒度抽象。

粗粒度的抽象

用抽象來(lái)處理迭代等任務(wù),使得需要維護(hù)的代碼變得更少,因此可能出現(xiàn)錯(cuò)誤的地方也就更少。清單 2 顯示了一個(gè)更簡(jiǎn)潔的數(shù)字分類(lèi)器,用 Groovy 編寫(xiě),借用了 Groovy 的函數(shù)風(fēng)格方法:

清單 2. Groovy 數(shù)字分類(lèi)器

  1. import static java.lang.Math.sqrt  
  2.    
  3. class Classifier {  
  4.   def static isFactor(number, potential) {  
  5.     number % potential == 0;  
  6.   }  
  7.    
  8.   def static factorsOf(number) {  
  9.     (1..number).findAll { isFactor(number, it) }  
  10.   }  
  11.    
  12.   def static sumOfFactors(number) {  
  13.     factorsOf(number).inject(0, {i, j -> i + j})  
  14.   }  
  15.    
  16.   def static isPerfect(number) {  
  17.     sumOfFactors(number) == 2 * number  
  18.   }  
  19.    
  20.   def static isAbundant(number) {  
  21.     sumOfFactors(number) > 2 * number  
  22.   }  
  23.    
  24.   def static isDeficient(number) {  
  25.     sumOfFactors(number) < 2 * number  
  26.   }  

清單 2 中的代碼使用很少的代碼完成 清單 1 的所有工作(減去緩存總數(shù),這會(huì)重新出現(xiàn)在下面的示例中)。例如,用于確定factorsOf() 中的系數(shù)的迭代消失了,替換為使用 findAll() 方法,它接受一個(gè)具有我的篩選器條件的代碼塊(一個(gè)高階函數(shù))。Groovy 甚至允許使用更簡(jiǎn)潔的代碼塊,它允許單參數(shù)塊使用 it 作為隱含參數(shù)名稱(chēng)。同樣,sumOfFactors() 方法使用了 inject(),它(使用 0 作為種子值)將代碼塊應(yīng)用于每個(gè)元素,將每個(gè)對(duì)減少為單一的值。{i, j -> i + j} 代碼塊返回兩個(gè)參數(shù)的總和;每次將列表 “折疊” 成一個(gè)對(duì)時(shí),都會(huì)應(yīng)用此塊,產(chǎn)生總和。

Java 開(kāi)發(fā)人員習(xí)慣于框架 級(jí)別的重用;在面向?qū)ο蟮恼Z(yǔ)言中進(jìn)行重用所需的必要構(gòu)件需要非常大的工作量,他們通常會(huì)將精力留給更大的問(wèn)題。函數(shù)式語(yǔ)言在更細(xì)化的級(jí)別提供重用,在列表和映射等基本數(shù)據(jù)結(jié)構(gòu)之上通過(guò)高階函數(shù)提供定制,從而實(shí)現(xiàn)重用。

少量數(shù)據(jù)結(jié)構(gòu),大量操作

在面向?qū)ο蟮拿钍骄幊陶Z(yǔ)言中,重用的單元是類(lèi)以及與這些類(lèi)進(jìn)行通信的消息,這些信息是在類(lèi)圖中捕獲的。該領(lǐng)域的開(kāi)創(chuàng)性著作是《設(shè)計(jì)模式: 可復(fù)用面向?qū)ο筌浖幕A(chǔ)》,至少為每個(gè)模式提供一個(gè)類(lèi)圖。在 OOP 的世界中,鼓勵(lì)開(kāi)發(fā)人員創(chuàng)建獨(dú)特的數(shù)據(jù)結(jié)構(gòu),以方法的形式附加特定的操作。函數(shù)式編程語(yǔ)言嘗試采用不同的方式來(lái)實(shí)現(xiàn)重用。它們更喜歡一些關(guān)鍵的數(shù)據(jù)結(jié)構(gòu)(如列表、集和映射),并且在這些數(shù)據(jù)結(jié)構(gòu)上采用高度優(yōu)化的操作。傳遞數(shù)據(jù)結(jié)構(gòu)和高階函數(shù),以便 “插入” 這種機(jī)制,針對(duì)某一特定用途對(duì)其進(jìn)行定制。例如,在 清單 2 中,findAll() 方法接受使用一個(gè)代碼塊作為 “插件” 高階函數(shù)(該函數(shù)確定了篩選條件),而該機(jī)制以有效方式應(yīng)用了篩選條件,并返回經(jīng)過(guò)篩選的列表。

函數(shù)級(jí)的封裝支持在比構(gòu)建自定義類(lèi)結(jié)構(gòu)更細(xì)的基礎(chǔ)級(jí)別上進(jìn)行重用。此方法的優(yōu)勢(shì)之一已經(jīng)體現(xiàn)在 Clojure 中。最近,庫(kù)中的一些巧妙創(chuàng)新重寫(xiě)了 map 函數(shù),使它可以自動(dòng)并行化,這意味著所有映射操作都可以受益于沒(méi)有開(kāi)發(fā)人員干預(yù)的性能提升。

例如,考慮一下解析 XML 的情況。大量的框架可用于在 Java 中完成這個(gè)任務(wù),每個(gè)框架都有自定義的數(shù)據(jù)結(jié)構(gòu)和方法語(yǔ)義(例如,SAX 與 DOM)。Clojure 將 XML 解析為一個(gè)標(biāo)準(zhǔn)的 Map 結(jié)構(gòu),而不是強(qiáng)迫您使用自定義的數(shù)據(jù)結(jié)構(gòu)。因?yàn)?Clojure 中包含大量與映射配合使用的工具,如果使用內(nèi)置的列表理解函數(shù) for,那么執(zhí)行 XPath 樣式的查詢(xún)就會(huì)很簡(jiǎn)單,如清單 3 所示:

清單 3. 將 XML 解釋為 Clojure

  1. (use 'clojure.xml)  
  2.    
  3. (def WEATHER-URI "http://weather.yahooapis.com/forecastrss?w=%d&u=f")  
  4.    
  5. (defn get-location [city-code]  
  6.   (for [x (xml-seq (parse (format WEATHER-URI city-code)))  
  7.         :when (= :yweather:location (:tag x))]  
  8.     (str (:city (:attrs x)) "," (:region (:attrs x)))))  
  9.    
  10. (defn get-temp [city-code]  
  11.   (for [x (xml-seq (parse (format WEATHER-URI city-code)))  
  12.         :when (= :yweather:condition (:tag x))]  
  13.     (:temp (:attrs x))))  
  14.    
  15. (println "weather for " (get-location 12770744"is " (get-temp 12770744)) 

在 清單 3 中,我訪問(wèn)雅虎的氣象服務(wù)來(lái)獲取某個(gè)給定城市的氣象預(yù)報(bào)。因?yàn)?Clojure 是 Lisp 的一個(gè)變體,所有從內(nèi)部讀取是最簡(jiǎn)單的。對(duì)服務(wù)端點(diǎn)的實(shí)際調(diào)用發(fā)生在 (parse (format WEATHER-URI city-code)) 上,它使用了 String 的 format() 函數(shù)將 city-code嵌入字符串。列表理解函數(shù) for 放置了解析后的 XML,使用 xml-seq 將它投放到名稱(chēng)為 x 的可查詢(xún)映射中。:when 謂詞確定了匹配條件;在本例中,我要搜索一個(gè)標(biāo)簽(轉(zhuǎn)換成一個(gè) Clojure 關(guān)鍵字) :yweather:condition。

如欲了解從數(shù)據(jù)結(jié)構(gòu)中讀取值所用的語(yǔ)法,那么查看該語(yǔ)法中包含的內(nèi)容會(huì)非常有用。在解析的時(shí)候,氣象服務(wù)的相關(guān)調(diào)用會(huì)返回在此摘錄中顯示的數(shù)據(jù)結(jié)構(gòu):

  1. ({:tag :yweather:condition, :attrs {:text Fair, :code 34, :temp 62, :date Tue,   
  2.    04 Dec 2012 9:51 am EST}, :content nil}) 

因?yàn)橐呀?jīng)為了與映射配合使用而優(yōu)化了 Clojure,所以關(guān)鍵字在包含它們的映射上成為了函數(shù)。在 清單 3 中,對(duì) (:tag x) 的調(diào)用是一個(gè)縮寫(xiě),它等同于 “從存儲(chǔ)在 x 中的映射檢索與 :tag 鍵對(duì)應(yīng)的值”。因此,:yweather:condition 產(chǎn)生與該鍵關(guān)聯(lián)的映射值,其中包括我使用相同語(yǔ)法從中提取 :temp 的 attrs。

最初,Clojure 中令人生畏的細(xì)節(jié)之一是:與映射和其他核心數(shù)據(jù)結(jié)構(gòu)進(jìn)行交互的方法似乎有無(wú)限多種。然而,它反映了這樣一個(gè)事實(shí):在 Clojure 中,大多數(shù)內(nèi)容都嘗試解決這些核心的、優(yōu)化的數(shù)據(jù)結(jié)構(gòu)。它沒(méi)有將解析的 XML 困在一個(gè)獨(dú)特的框架中,相反,它試圖將其轉(zhuǎn)換為一個(gè)已存在相關(guān)工具的現(xiàn)有結(jié)構(gòu)。

對(duì)基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)的依賴(lài)性的優(yōu)點(diǎn)體現(xiàn)在 Clojure 的 XML 庫(kù)中。為了遍歷樹(shù)形結(jié)構(gòu)(如 XML 文檔),1997 年創(chuàng)建了一個(gè)有用的數(shù)據(jù)結(jié)構(gòu),名為 zipper(參閱 參考資料)。zipper 通過(guò)提供坐標(biāo)系方向,讓您可以結(jié)構(gòu)性地導(dǎo)航樹(shù)。例如,可以從樹(shù)的根開(kāi)始,發(fā)出 (-> z/down z/down z/left) 等命令,導(dǎo)航到第二級(jí)的左側(cè)元素。Clojure 中已經(jīng)有現(xiàn)成的函數(shù)可將解析的 XML 轉(zhuǎn)換為 zipper,在整個(gè)樹(shù)形結(jié)構(gòu)中實(shí)現(xiàn)一致的導(dǎo)航。

#p#

新的、不同的工具

函數(shù)式編程提供了新的工具類(lèi)型,以?xún)?yōu)雅的方式解決棘手的問(wèn)題。例如,Java 開(kāi)發(fā)人員不習(xí)慣盡能延遲生成其值的惰性 數(shù)據(jù)結(jié)構(gòu)。而未來(lái)的函數(shù)式語(yǔ)言將對(duì)這種高級(jí)特性提供支持,一些框架將此功能加裝到 Java 中。例如,清單 4 所示的數(shù)字分類(lèi)器版本使用了 Totally Lazy 框架:

清單 4. Java 數(shù)字分類(lèi)器通過(guò) Totally Lazy 使用惰性和函數(shù)式數(shù)據(jù)結(jié)構(gòu)

  1. import com.googlecode.totallylazy.Predicate;  
  2. import com.googlecode.totallylazy.Sequence;  
  3.    
  4. import static com.googlecode.totallylazy.Predicates.is;  
  5. import static com.googlecode.totallylazy.numbers.Numbers.*;  
  6. import static com.googlecode.totallylazy.predicates.WherePredicate.where;  
  7.    
  8. public class Classifier {  
  9.   public static Predicate<Number> isFactor(Number n) {  
  10.       return where(remainder(n), is(zero));  
  11.   }  
  12.    
  13.   public static Sequence<Number> getFactors(final Number n){  
  14.       return range(1, n).filter(isFactor(n));  
  15.   }  
  16.    
  17.   public static Sequence<Number> factors(final Number n) {  
  18.       return getFactors(n).memorise();  
  19.   }  
  20.    
  21.   public static Number sumFactors(Number n){  
  22.       return factors(n).reduce(sum);  
  23.   }  
  24.    
  25.   public static boolean isPerfect(Number n){  
  26.       return equalTo(n, subtract(sumFactors(n), n));  
  27.   }  
  28.    
  29.   public static boolean isAbundant(Number n) {  
  30.     return greaterThan(subtract(sumFactors(n), n), n);  
  31.   }  
  32.    
  33.   public static boolean isDeficient(Number n) {  
  34.     return lessThan(subtract(sumFactors(n), n), n);  
  35.   }  
  36.    

Totally Lazy 增加了惰性集合和流暢接口方法,大量使用靜態(tài)導(dǎo)入,使代碼具有可讀性。如果您羨慕下一代語(yǔ)言中的某些特性,那么一些研究可能會(huì)提供可以解決某個(gè)特定問(wèn)題的特定擴(kuò)展。

讓語(yǔ)言遷就問(wèn)題

大多數(shù)開(kāi)發(fā)人員都將他們的工作誤解為接受一個(gè)復(fù)雜的業(yè)務(wù)問(wèn)題,將它轉(zhuǎn)換成 Java 等語(yǔ)言。他們的這種誤解是因?yàn)?Java 并不是一種特別靈活的語(yǔ)言,它迫使您讓自己的想法適應(yīng)于已經(jīng)存在的剛性結(jié)構(gòu)。但是,當(dāng)開(kāi)發(fā)人員使用可塑語(yǔ)言時(shí),他們看到了讓語(yǔ)言遷就問(wèn)題,而不是讓問(wèn)題遷就語(yǔ)言的機(jī)會(huì)。像 Ruby(它為領(lǐng)域特定語(yǔ)言 (DSL) 提供了比主流更友好的支持)等語(yǔ)言證明了這種潛在可能?,F(xiàn)代函數(shù)式語(yǔ)言甚至走得更遠(yuǎn)。Scala 旨在協(xié)調(diào)內(nèi)部 DSL 的托管,并且所有 Lisp(包括 Clojure)都可以提供無(wú)與倫比的靈活性,使開(kāi)發(fā)人員能夠讓語(yǔ)言適應(yīng)問(wèn)題。例如,清單 5 使用了 Scala 中的 XML 基元來(lái)實(shí)現(xiàn) 清單 3 的天氣示例:

清單 5. Scala 的 XML 語(yǔ)法修飾

  1. import scala.xml._  
  2. import java.net._  
  3. import scala.io.Source  
  4.    
  5. val theUrl = "http://weather.yahooapis.com/forecastrss?w=12770744&u=f" 
  6.    
  7. val xmlString = Source.fromURL(new URL(theUrl)).mkString  
  8. val xml = XML.loadString(xmlString)  
  9.    
  10. val city = xml \\ "location" \\ "@city" 
  11. val state = xml \\ "location" \\ "@region" 
  12. val temperature = xml \\ "condition" \\ "@temp" 
  13.    
  14. println(city + ", " + state + " " + temperature) 

Scala 是為獲得可塑性而設(shè)計(jì)的,它支持操作符重載和隱式類(lèi)型等擴(kuò)展。在 清單 5 中,Scala 被擴(kuò)展為可以使用 \\ 操作符支持類(lèi)似 XPath 的查詢(xún)。

與語(yǔ)言的趨勢(shì)相一致

函數(shù)式編程的目標(biāo)之一是最大程度地減少可變狀態(tài)。在 清單 1 中,有兩種類(lèi)型的共享狀態(tài)清單。_factors 和 _number 都存在,它們使代碼測(cè)試變得更容易(編寫(xiě)原代碼版本是為了說(shuō)明最大可測(cè)試性),并可以折疊成更大的函數(shù),從而消除它們。但是,_sum 是因?yàn)楦鞣N原因而存在。我預(yù)計(jì),這段代碼的用戶(hù)可能需要檢查多個(gè)分類(lèi)。(例如,如果一個(gè)完美的檢查失敗,那么下一次我可能會(huì)檢查百分比。)合計(jì)系數(shù)總數(shù)的操作可能很昂貴,所以我為它創(chuàng)建了一個(gè)經(jīng)過(guò)惰性初始化的訪問(wèn)器。在第一次調(diào)用時(shí),它會(huì)計(jì)算總和,并將它存儲(chǔ)在 _sum 成員變量中,以便優(yōu)化未來(lái)的調(diào)用。

像垃圾收集一樣,現(xiàn)在緩存也可以降級(jí)用于語(yǔ)言。清單 2 中的 Groovy 數(shù)字分類(lèi)器忽略了 清單 1 中總數(shù)的惰性初始化。如果想要實(shí)現(xiàn)同樣的功能,可以修改分類(lèi)器,如清單 6 所示:

清單 6. 手動(dòng)添加一個(gè)緩存

  1. class ClassifierCachedSum {  
  2.   private sumCache  
  3.    
  4.   ClassifierCachedSum() {  
  5.     sumCache = [:]  
  6.   }  
  7.    
  8.   def sumOfFactors(number) {  
  9.     if (sumCache.containsKey(number))  
  10.       return sumCache[number]  
  11.     else {  
  12.       def sum = factorsOf(number).inject(0, {i, j -> i + j})  
  13.       sumCache.putAt(number, sum)  
  14.       return sum  
  15.     }  
  16.   }  
  17.   // ... other code omitted 

在最新版的 Groovy 中,清單 6 中的代碼不再是必要的??紤]使用清單 7 中的改進(jìn)版的分類(lèi)器:

清單 7. 備忘數(shù)字分類(lèi)器

  1. class ClassifierMemoized {  
  2.   def static dividesBy = { number, potential ->  
  3.     number % potential == 0 
  4.   }  
  5.   def static isFactor = dividesBy.memoize()  
  6.    
  7.   def static factorsOf(number) {  
  8.     (1..number).findAll { i -> isFactor.call(number, i) }  
  9.   }  
  10.    
  11.   def static sumFactors = { number ->  
  12.     factorsOf(number).inject(0, {i, j -> i + j})  
  13.   }  
  14.   def static sumOfFactors = sumFactors.memoize()  
  15.    
  16.   def static isPerfect(number) {  
  17.     sumOfFactors(number) == 2 * number  
  18.   }  
  19.    
  20.   def static isAbundant(number) {  
  21.     sumOfFactors(number) > 2 * number  
  22.   }  
  23.    
  24.   def static isDeficient(number) {  
  25.     sumOfFactors(number) < 2 * number  
  26.   }  

任何純函數(shù)(沒(méi)有副作用的函數(shù))都可以備忘,比如 清單 7 中的 sumOfFactors() 方法。備忘函數(shù)允許運(yùn)行時(shí)緩存重復(fù)出現(xiàn)的值,從而消除手工編寫(xiě)緩存的需要。事實(shí)上,請(qǐng)注意執(zhí)行實(shí)際工作的 getFactors() 和 factors() 方法之間的關(guān)系,該方法是備忘版本的getFactors()。Totally Lazy 還為 Java 增加了備忘功能,這是反饋到主流中的另一個(gè)高級(jí)函數(shù)特性。

由于運(yùn)行時(shí)獲得了更多的能力并且有多余的開(kāi)銷(xiāo),開(kāi)發(fā)人員可以將繁忙的工作割讓給語(yǔ)言,將我們解放出來(lái),去思考更重要的問(wèn)題。Groovy 中的備忘功能就是眾多示例中的一個(gè);因?yàn)榛A(chǔ)運(yùn)行時(shí)允許這樣做,所有現(xiàn)代語(yǔ)言都添加了函數(shù)式構(gòu)造,包括 Totally Lazy 等框架。

結(jié)束語(yǔ)

因?yàn)檫\(yùn)行時(shí)的能力變得更強(qiáng),并且語(yǔ)言獲得了更強(qiáng)大的抽象,所以開(kāi)發(fā)世界變得更加函數(shù)化,這使開(kāi)發(fā)人員可以花費(fèi)更多的時(shí)間來(lái)思考結(jié)果的影響,而不是思考如何生成結(jié)果。由于高階函數(shù)等抽象出現(xiàn)在語(yǔ)言中,它們將成為高度優(yōu)化的操作的自定義機(jī)制。您不需要?jiǎng)?chuàng)建框架來(lái)處理問(wèn)題(如 XML),您可以將其轉(zhuǎn)換成您已經(jīng)可以使用工具來(lái)處理的數(shù)據(jù)結(jié)構(gòu)。

隨著第 20 期文章的發(fā)布,函數(shù)式思維 將告一段落,我將準(zhǔn)備開(kāi)始一個(gè)新的系列,探索下一代的 JVM 語(yǔ)言。Java 下一代 會(huì)讓您對(duì)不久的將來(lái)有一個(gè)大致了解,并幫助您對(duì)必須投入新語(yǔ)言學(xué)習(xí)的時(shí)間作出明智選擇。

原文鏈接:http://www.ibm.com/developerworks/cn/java/j-ft20/index.html?ca=drs-

責(zé)任編輯:林師授 來(lái)源: IBM Developerworks
相關(guān)推薦

2024-10-29 11:05:26

2021-08-03 11:09:41

智能手機(jī)功能技術(shù)

2018-04-24 10:38:23

項(xiàng)目開(kāi)發(fā)代碼

2019-10-28 15:10:31

懶人剪輯運(yùn)動(dòng)相機(jī)移動(dòng)應(yīng)用

2020-08-13 09:49:43

WAF應(yīng)用安全網(wǎng)絡(luò)安全

2018-05-29 12:00:51

前端工作互聯(lián)網(wǎng)

2022-06-16 20:56:53

邊緣計(jì)算

2014-09-05 10:15:41

函數(shù)式編程

2009-09-24 09:20:10

數(shù)據(jù)中心管理

2024-02-21 14:28:09

智能家居物聯(lián)網(wǎng)安全

2021-09-11 22:57:22

手機(jī)價(jià)格配置

2013-08-15 11:04:40

LinuxSUSE

2024-03-13 10:29:39

2015-06-30 10:35:51

數(shù)據(jù)中心

2024-07-19 16:31:57

2022-01-26 23:18:21

手機(jī)屏幕電池

2021-01-19 09:28:07

邊緣數(shù)據(jù)云計(jì)算

2021-03-25 09:41:43

前端Monorepo技術(shù)熱點(diǎn)

2021-09-18 10:41:45

手機(jī)廠商安全

2021-08-24 00:14:10

手機(jī)工具游戲
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)