欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
函數式思維: 運用函數式思維,第 2 部分

在本系列的 第一期 中,我首先討論函數編程的一些特點(diǎn),并演示如何在 Java 和其他函數語(yǔ)言中體現這些觀(guān)念。在本文中,我將繼續討論這些概念,講解一級函數、優(yōu)化和閉包。但本期的內在主題是控制:什么時(shí)候想要控制、什么時(shí)候需要控制、什么時(shí)候應該放棄控制。

一級(First-class)函數和控制

我在上一部分最后通過(guò)使用 Functional Java 庫(見(jiàn) 參考資料),演示了用函數 isFactor()factorsOf() 方法實(shí)現數字分類(lèi)器,如清單 1 所示:


清單 1. 數字分類(lèi)器的函數版本
				public class FNumberClassifier {    public boolean isFactor(int number, int potential_factor) {        return number % potential_factor == 0;    }    public List<Integer> factorsOf(final int number) {        return range(1, number+1).filter(new F<Integer, Boolean>() {            public Boolean f(final Integer i) {                return number % i == 0;            }        });    }    public int sum(List<Integer> factors) {        return factors.foldLeft(fj.function.Integers.add, 0);    }    public boolean isPerfect(int number) {        return sum(factorsOf(number)) - number == number;    }    public boolean isAbundant(int number) {        return sum(factorsOf(number)) - number > number;    }    public boolean isDeficiend(int number) {        return sum(factorsOf(number)) - number < number;    }}    

isFactor()factorsOf() 方法中,我停止了對框架循環(huán)算法的控制 — 它決定如何通過(guò)最好的方式遍歷所有數字。如果框架(或者 — 如果您選擇一門(mén)函數語(yǔ)言,如 Clojure 或 Scala — 語(yǔ)言)能優(yōu)化底層實(shí)現,那么您就可以自動(dòng)從中獲益。盡管您一開(kāi)始可能不愿放棄這么多控制,但要知道這是編程語(yǔ)言和運行時(shí)的普遍趨勢:隨著(zhù)時(shí)代發(fā)展,開(kāi)發(fā)人員會(huì )越來(lái)越遠離那些平臺能更有效處理的細節。我從不擔心 JVM 的內存管理,因為平臺可以讓我忘了它。當然,有時(shí)候它也會(huì )讓事情變得更復雜,但是對于您從日復一日的編碼中獲得的收益來(lái)說(shuō),這是值得的。函數語(yǔ)言結構,如高階和一級函數,能讓我對抽象的理解更進(jìn)一步,讓我更多地將精力放在代碼能做什么 而不是怎么做 上。

即使使用 Functional Java 框架,在 Java 中以這種風(fēng)格編程也很麻煩,因為這種語(yǔ)言并沒(méi)有真正的這類(lèi)語(yǔ)法和結構。在支持的語(yǔ)言中進(jìn)行函數編碼是什么樣的呢?

Clojure 中的分類(lèi)器

Clojure 是一種用于 JVM 的 Lisp(見(jiàn) 參考資料)??纯从?Clojure 編寫(xiě)的數字分類(lèi)器,如清單 2 所示:


清單 2. 數字分類(lèi)器的 Clojure 實(shí)現
				(ns nealford.perfectnumbers)(use '[clojure.contrib.import-static :only (import-static)])(import-static java.lang.Math sqrt)(defn is-factor?[factor number]  (= 0 (rem number factor)))(defn factors [number]   (set (for [n (range 1 (inc number)) :when (is-factor? n number)] n)))(defn sum-factors [number]     (reduce + (factors number)))(defn perfect?[number]  (= number (- (sum-factors number) number)))(defn abundant?[number]  (< number (- (sum-factors number) number)))(defn deficient?[number]  (> number (- (sum-factors number) number)))

即使您不是熟練的 Lisp 開(kāi)發(fā)人員,也能輕松讀懂 清單 2 中的大多數代碼 — 您可以學(xué)著(zhù)從內向外讀。例如,is-factor? 方法有兩個(gè)參數,它判斷 number 除以 factor 時(shí)余數是否等于零。同樣,perfect?、abundant?deficient? 方法也很容易理解,尤其是參考一下 清單 1 的 Java 實(shí)現之后。

sum-factors 方法使用內置的 reduce 方法。sum-factors 一次減少一個(gè)列表元素,它使用函數(本例中,是 +)作為每個(gè)元素的第一個(gè)參數。reduce 方法在幾種語(yǔ)言和框架中會(huì )有不同的形式;清單 1foldLeft() 方法的 Functional Java 版本。factors 方法會(huì )返回一個(gè)數字列表,因此我一次處理一個(gè)數字,將每個(gè)元素加入和中,該和數就是 reduce 的返回值。您會(huì )看到,一旦您習慣了從高階和一級函數的角度思考,您就能減少(一語(yǔ)雙關(guān))代碼中無(wú)用的部分。

factors 方法可能看上去像一個(gè)隨機符號集。但如果您理解了列表的含義,您就知道這么做是有道理的,這是 Clojure 中強大的列表操作功能之一。和之前一樣,從內向外閱讀 factors 就很容易理解。不要被這些混在一起的語(yǔ)言術(shù)語(yǔ)搞糊涂。Clojure 中的 for 關(guān)鍵詞并不表示 for 循環(huán)。相反,將它當成是所有過(guò)濾和轉換結構的來(lái)源。本例中,我讓它過(guò)濾從 1 到(number + 1)范圍的數字,使用 is-factor? 謂詞(我在之前的 清單 2 中定義的 is-factor 方法 — 請注意一類(lèi)函數的大量使用),返回匹配的數字。從此操作返回的是一組滿(mǎn)足過(guò)濾標準的數字列表,我將其放入一個(gè)集合來(lái)刪除重復值。

盡管學(xué)習一門(mén)新的語(yǔ)言很麻煩,但對于函數語(yǔ)言,當您了解其特點(diǎn)后,學(xué)起來(lái)就容易得多。

優(yōu)化

轉換到函數樣式的收益之一就是能利用語(yǔ)言或框架提供的高階函數。那么不想放棄控制的時(shí)候呢?我在之前的例子中,把遍歷機制的內部行為比作內存管理器的內部運作:大多數時(shí)候,您會(huì )很高興不用關(guān)心那些細節。但有時(shí)候您會(huì )關(guān)心這些問(wèn)題,特別是在遇到優(yōu)化或類(lèi)似任務(wù)時(shí)。

在 “運用函數式思維,第 1 部分” 的數字分類(lèi)器的兩個(gè) Java 版本中,我優(yōu)化了確定因子的代碼。原先是簡(jiǎn)單的使用取模運算符(%)的實(shí)現,它非常低效,它自己檢查從 2 到目標數的每個(gè)數字,確定是否是因子。因子是成對出現的,可以通過(guò)這點(diǎn)來(lái)優(yōu)化算法。例如,如果您查找 28 的因子,當您找到 2 時(shí),那么同時(shí)會(huì )找到 14。如果您成對獲取因子,您只需要檢查到目標數的平方根即可。

在 Java 版本中很容易完成的實(shí)現似乎在 Functional Java 版本中很難做到,因為我無(wú)法直接控制遍歷機制。但作為函數式思維的一部分,您需要放棄這種控制觀(guān)念,學(xué)會(huì )用另一種控制。

我會(huì )以函數式思維重新說(shuō)明原來(lái)的問(wèn)題:過(guò)濾所有 1 到 number 的因子,只保留匹配 isFactor() 謂詞的因子。其實(shí)現見(jiàn)清單 3:


清單 3. isFactor() 方法
				public List<Integer> factorsOf(final int number) {    return range(1, number+1).filter(new F<Integer, Boolean>() {        public Boolean f(final Integer i) {            return number % i == 0;        }    });}

盡管看上去很優(yōu)雅,但 清單 3 中的代碼效率很低,因為它會(huì )檢查每個(gè)數。在了解優(yōu)化(成對獲取因子,只檢查到平方根)之后,重述問(wèn)題如下:

  1. 過(guò)濾目標數的所有因子,從 1 到其平方根。
  2. 用這些因子除以目標數,以獲得對稱(chēng)因子,并將它加入因子列表中。

記住了這個(gè)目標,我就可以用 Functional Java 庫寫(xiě)出 factorsOf() 方法的優(yōu)化版本,如清單 4 所示:


清單 4. 優(yōu)化的因子查找方法
				public List<Integer> factorsOfOptimzied(final int number) {    List<Integer> factors =         range(1, (int) round(sqrt(number)+1))        .filter(new F<Integer, Boolean>() {            public Boolean f(final Integer i) {                return number % i == 0;            }});    return factors.append(factors.map(new F<Integer, Integer>() {                                      public Integer f(final Integer i) {                                          return number / i;                                      }}))                                      .nub();}

清單 4 中的代碼是基于我之前講過(guò)的算法,其中有一些獨特的語(yǔ)法,這是 Functional Java 框架所必需的。首先,獲取數的范圍是從 1 到目標數的平方根加 1(確保能取到所有因子)。第二步,根據與之前版本一樣的取模操作方法過(guò)濾結果,這些都包含在 Functional Java 代碼段中。我將過(guò)濾后的列表放在 factors 變量中。第四步(從內到外閱讀),獲取因子列表,并執行 map() 函數,它在代碼中對每個(gè)元素進(jìn)行處理(將每個(gè)元素 映射到一個(gè)新值),從而產(chǎn)生一個(gè)新的列表。因子列表中包含到目標數平方根的所有因子;需要除以每個(gè)數以獲得對稱(chēng)因子,而 map() 方法就是完成這個(gè)任務(wù)的。第五步,現在已經(jīng)有了對稱(chēng)因子列表,我將它添加到原來(lái)的列表中。最后一步,有個(gè)情況我必需考慮,因子保存在 List 中,而不是 Set 中。List 方法對于這些類(lèi)型操作很方便,但我的算法有個(gè)副作用,就是出現整數平方根時(shí),會(huì )有重復。例如,如果目標數是 16,平方根的整部部分 4 會(huì )在因子列表中出現兩次。為了能繼續使用方便的 List 方法,我只要在最后調用 nub() 方法,它將刪除所有重復值。

一般情況下在使用高級抽象,比如函數編程時(shí),您不需要了解實(shí)現細節,但這并不意味這在必要的情況下,就無(wú)法了解。Java 平臺大多數情況下不需要您知道底層內容,但如果您下定決心,您就可以了解到你想達到的層次的內容。同樣,在函數編程結構中,您可以把細節留給抽象機制,在出現問(wèn)題的時(shí)候才去關(guān)注它。

到目前為止所演示的 Functional Java 代碼中,最精華的部分是代碼的語(yǔ)法,它使用了泛型和匿名內部類(lèi)作為偽代碼段和閉包類(lèi)型結構。閉包是函數語(yǔ)言的共有特征之一。為什么它們用處這么大?

閉包有什么特別之處?

閉包是一個(gè)會(huì )對它內部引用的所有變量進(jìn)行隱式綁定的函數。換句話(huà)說(shuō),這個(gè)函數(或方法)會(huì )對它引用的所有內容關(guān)閉上下文。閉包經(jīng)常會(huì )在函數語(yǔ)言和框架中用作可移動(dòng)執行機制,會(huì )作為轉換代碼傳遞給高階函數,如 map()。Functional Java 使用匿名內部閉包來(lái)模仿 “實(shí)際” 閉包行為,但不能一直這樣做,因為 Java 不支持閉包。這意味著(zhù)什么?

清單 5 是一個(gè)樣例,演示了閉包的特別之處。這是用 Groovy 編寫(xiě)的,它通過(guò)代碼段塊機制支持閉包。


清單 5. Groovy 代碼演示閉包
				def makeCounter() {  def very_local_variable = 0  return { return very_local_variable += 1 }}c1 = makeCounter()c1()c1()c1()c2 = makeCounter()println "C1 = ${c1()}, C2 = ${c2()}"http:// output:C1 = 4, C2 = 1

makeCounter() 方法首先定義了一個(gè)具有適當名稱(chēng)的本地變量,然后返回使用該變量的代碼段。請注意,makeCounter() 方法的返回類(lèi)型是代碼段,而不是值。代碼段做的事就是增加本地變量的值并返回。我在代碼中設置了顯式 return 調用,這在 Groovy 中都是可選的,但如果不用,代碼就更難懂了!

為了能使用 makeCounter() 方法,我將代碼段指定為 C1 變量,然后調用三次。我使用了 Groovy 的語(yǔ)法糖(syntactic sugar)來(lái)執行此代碼段,結果放置在代碼段變量旁邊的圓括號中。接下來(lái),我再次調用 makeCounter(),將代碼段的一個(gè)新實(shí)例指定為 C2。最后,我再次執行 C1C2。請注意,每個(gè)代碼段都能追蹤到 very_local_variable 的一個(gè)單獨實(shí)例。這就是封閉的上下文 的含義。即使在方法內部定義本地變量,代碼段仍會(huì )綁定到該變量,因為變量引用了代碼段,這意味著(zhù)在代碼段可用時(shí),變量必須能追蹤到它。

在 Java 中實(shí)現相同操作的最簡(jiǎn)單的方法如清單 6:


清單 6. Java 中的 Counter
				public class Counter {    private int varField;    public Counter(int var) {        varField = var;    }    public static Counter makeCounter() {        return new Counter(0);    }    public int execute() {        return ++varField;    }}  

Counter 類(lèi)進(jìn)行一些變化都可以,但您一定要自己管理狀態(tài)。以上演示了為什么閉包體現了函數思想:讓運行時(shí)管理狀態(tài)。與其強迫自己處理字段創(chuàng )建和原始狀態(tài)(包括在多線(xiàn)程環(huán)境中使用代碼的可怕前景),還不如讓語(yǔ)言或框架默默地管理狀態(tài)。

在以后的 Java 版本中會(huì )有閉包(關(guān)于本話(huà)題的討論已超出本文范圍)。Java 中包含它們將有兩項收益。首先,在改進(jìn)語(yǔ)法的同時(shí),大大簡(jiǎn)化框架和庫作者的能力。第二,為所有在 JVM 上運行的語(yǔ)言提供一個(gè)底層的共同基礎。即使很多 JVM 語(yǔ)言支持閉包,但它們都實(shí)現自己的版本,這造成在語(yǔ)言之間傳遞閉包非常麻煩。如果 Java 定義了一個(gè)單一格式,那么其他所有語(yǔ)言都能利用它。

結束語(yǔ)

回避對底層細節的控制是軟件開(kāi)發(fā)的普遍趨勢。我們很高興不用再操心垃圾回收、內存管理和硬件差異。函數編程代表了下一個(gè)抽象階段:將更加瑣碎的細節如遍歷、并發(fā)性和狀態(tài)盡可能留給運行時(shí)處理。這并不意味著(zhù)您在需要的時(shí)候無(wú)法再控制它們 — 是您想要控制,而不是被迫控制。

在下一篇文章中,我將繼續探討 Java 及同類(lèi)語(yǔ)言中的函數編程結構,我將會(huì )介紹 curryingpartial method application。


參考資料

學(xué)習

獲得產(chǎn)品和技術(shù)

討論

關(guān)于作者

Neal Ford 是一家全球性 IT 咨詢(xún)公司 ThoughtWorks 的軟件架構師和 Meme Wrangler。他的工作還包括設計和開(kāi)發(fā)應用程序、教材、雜志文章、課件和視頻/DVD 演示,而且他是各種技術(shù)書(shū)籍的作者或編輯,包括最近的新書(shū) The Productive Programmer 。他主要的工作重心是設計和構建大型企業(yè)應用程序。他還是全球開(kāi)發(fā)人員會(huì )議上的國際知名演說(shuō)家。請訪(fǎng)問(wèn)他的 Web 站點(diǎn)。

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
折半查找算法
如何在Excel中求N次方和N次方根?
SQRT 函數 (三角與數學(xué)函數)
利用 AWK 的數值計算功能提升工作效率
SQL Server中的窗口函數
Excel實(shí)用技巧大全(不斷更新中...)
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久