TOP
0
0
【23號簡體館日】限時三天領券享優惠!!
Scala函數式編程(簡體書)
滿額折

Scala函數式編程(簡體書)

人民幣定價:69 元
定  價:NT$ 414 元
優惠價:87360
領券後再享88折
海外經銷商無庫存,到貨日平均30天至45天
可得紅利積點:10 點
相關商品
商品簡介
作者簡介
名人/編輯推薦
目次
書摘/試閱

商品簡介

函數式程式設計(FP)是一種軟體發展風格,它注重不依賴於程式設計狀態的函數。函數式代碼易於測試和複用,容易實現併發,且不容易受到bug的攻擊。Scala是一種能很好支援函數式程式設計的新興JVM語言。本書是針對希望學習FP並將它應用於日常編碼中的程式師而寫的,內容包括:函數式程式設計的概念;函數式程式設計相關的各種"為什麼”和"怎麼做”;如何編寫多核程式;練習和檢測。

作者簡介

譯者
王宏江,現任挖財技術部資深架構師,從事軟體發展有十多年。曾在阿裡巴巴擔任架構師,參與過1688、來往等網站的基礎建設,以及淘寶類目等基礎業務重構,並在淘寶中介軟體負責過應用容器與分散式框架團隊。Tomcat方面的專家,善於診斷問題以及性能調優。有豐富的企業架構和大型互聯網技術架構經驗。同時也是函數式程式設計愛好者,和Scala佈道者。

名人/編輯推薦

√ Scala的入門好書有《快學Scala》,但講高階特性的僅此一本,空前絕後。
√ 自成體系已顯大師風範,親手設計習題更是罕見,本書習題可謂王冠之明珠。
√ 經典名著,豈敢怠慢!本書譯者是Scala社區翹楚,更有旗幟人物作序力薦。
√ 好書不僅給你知識,更帶來挑戰。本書實屬典範,語言|函數式|智慧全面挑戰。

關於本書
這不是一本關於 Scala 的書。這是一本介紹函數式程式設計(FP)的書——一種徹底的原則性很強的編寫軟體的方法。我們使用 Scala 作為交通工具到達那裡,但是你可以在課程中使用任何其他程式設計語言。當你讀完這本書,我們的目標是讓你牢固地掌握函數式程式設計的概念,在寫純函數式程式時感到舒適,並能夠為這些主題吸收新的素材,超越本書所覆蓋的這些內容。
這本書的結構
這本書由四部分組成。在第一部分,我們討論究竟什麼是函數式程式設計,並引入一些核心概念。在第一部分的章節裡做一個基礎的技術總覽,例如怎麼組織小的函數式程式、定義純函數式資料結構、錯誤處理,以及怎麼和狀態打交道。
在這基礎之上,第二部分是一系列的函數式設計教程。我們通過一些實際的函數式庫裡的例子,揭露設計它們的思維過程。
通過第二部分的庫函數的練習,會讓你清楚這些庫遵循某種模式並有一些冗餘。這將突出我們對一種新的更高階的抽象方式的需要,高階的抽象能夠寫出更加泛化的庫函數,我們將在第三部分引入這些抽象。這些都是對你的代碼推導非常具有威力的工具。一旦你掌握它們,會讓你成為一個極其富有生產力的程式師。
第四部分則填補了面向真實世界應用的其餘部分的空缺,這些部分包括執行 I/O(例如寫資料庫、檔或視頻顯示器)、使用可變狀態等,所有這些都是以純函數式的風格來實現的。
在本書的學習過程中,我們依賴大量的程式設計練習,仔細、有序的練習能夠説明你消化這些資料。要理解函數式程式設計,不僅僅是學習理論,你必須立即打開你的文字編輯器寫一些代碼,你必須將那些你已經學習的理論,轉換為工作中的實踐。
我們還提供了所有章節的線上筆記。每一章都有一段與之相關的討論,裡面提供了一些進一步閱讀的材料連結。這些章節筆記是可以被社區的讀者們擴展的,是一個可編輯的wiki:https://github.com/fpinscala/fpinscala/wiki。
受眾人群
本書適合至少有一些程式設計經驗的人參考閱讀。在我們心中有一些特定種類的讀者——那些對函數式程式設計好奇的,並且達到中級水準的 Java 或 C 程式師。但我們相信這本書也適合任何語言和任何經驗水準的程式師。
在讀這本書時你以前的專長經驗並不一定比你的動機和好奇心更重要。函數式程式設計充滿樂趣,但它也是一個有挑戰性的課題,尤其是對於那些更有經驗的程式師來說,因為它的思維方式可能不同於你以往有過的經驗。不管你程式設計多久,你必須準備以一個初學者的姿態來學習。
讀這本書並不需要之前有任何 Scala 經驗,但我們不會花大量的時間和篇幅討論 Scala 的語法和語言特性。我們將按照我們的需要,以最小化的方式來介紹 Scala,內容主要涉及的是其他素材。這些對 Scala 的介紹應該足以讓你開始練習。如果你對 Scala 語言有進一步的問題,你應該用另一本 Scala 的書作為你的補充閱讀(http://scala-lang.org/ documentation/books.html),或者在 Scala 語言文檔(http://scala-lang.org/documentation/)裡查找具體的問題。
如何閱讀這本書
你可以按序閱讀這本書,這四個部分的順序也是有意設計的,你可以按照自己舒適的方式在這些部分之間先休息一下,把你所學的應用到工作中,然後再回來繼續閱讀下一部分。例如,第四部分的內容,只有你閱讀完第一、二、三部分,並且非常熟悉函數式風格的程式設計之後才有意義。在第三部分之後,休息一下,嘗試做一些比章節裡更多的函數式程式練習,或許是個好主意。當然,最終都取決於你自己。
這本書裡大部分章節都有相似的結構。先引入一些新的思想或技術,用例子來解釋,然後通過一些練習來掌握。我們強烈建議你下載練習的原始程式碼,在學習每一章的時候做做練習。練習、提示以及答案都可以在這裡獲取:https://github.com/fpinscala/fpinscla。我們也鼓勵你訪問scala-functional Google 用戶組(https://groups.google.com/forum/#!topic/scala-functional/),以及在 irc.freenode.net 上的 #fp-in-scala IRC 頻道參與討論。
練習題會根據難度和重要性來標記。我們會按照自己的理解來標記題目是否很難,或者它對章節材料的理解是否可選。帶有困難標記的,我們會嘗試給你一些期待的思路——這只是我們所猜測的,或許你會發現一些沒有標記困難的問題很難解決,一些標記為困難的問題反而很容易。帶有可選標記的練習主要為增進你的見識,在不妨礙你閱讀後續的內容時你可以跳過。
這些練習用下面的圖示表示是否可選:
? 練習 1
在一個被填充的四邊形圖示後邊的練習表示它們是關鍵的練習。
? 練習 2
一個空心的四邊形表示練習是可選的。
這本書會貫穿很多例子,這些例子你要去嘗試實踐,而非僅僅只是閱讀。在你開始之前,應該確保 Scala 解譯器能運行。我們鼓勵你用自己的方式去試驗一下你看到的各種例子。幫你把事情搞明白的一個方法就是對它稍作改造,看看所做的改變對輸出結果有什麼影響。
有時我們會用 Scala 解譯器會話來演示一些代碼的運行或求值結果。這些將以解譯器的提示符 scala> 開頭。在提示符後邊緊跟的是要輸入或粘貼到解譯器的代碼,而下一行則是解譯器的回應,就像這樣:
scala> println("Hello, World!")
Hello, World!
代碼規範和下載
在清單或文本中的所有代碼都是類似這樣的等寬字體,以便於把它們和普通文本區分開。
Scala裡的關鍵字使用類似這樣的等寬粗體。很多清單裡都會包含代碼注釋,用於突出重要概念。
要下載這本書裡的樣例代碼,以及練習題和章節注釋裡的代碼,請到 https://github.com/fpinscala/fpinscala 或者出版商網站:www.manning.com/FunctionalProgramminginScala。
設定預期
雖然函數式程式設計對我們編寫軟體過程中的每個層面都產生了深遠的影響,但它仍需要時間。這是一個漸進的過程。在第 1 章先不要指望能被神奇的函數式程式設計所驚豔到。安排在開頭的一些原則都非常微妙,甚至看起來跟常識沒什麼區別。如果你覺得“這個我在不知道函數式程式設計的時候已經能夠做到了”,那就對了,這正是重點所在。大多數程式師已經在某種程度上做過函數式程式設計的事情,只是他們不知道而已。大多數人認為最佳實踐的很多東西 ( 例如,讓函數
只具有單一職責,或讓資料不可變 ) 都受到函數式程式設計的啟發。我們只是發現在這些最佳實踐下面的原則,找出它們的邏輯結論。
在讀這本書的時候有很大的可能你將同時要學習 Scala 語法和函數式程式設計。一開始這些代碼可能看起來很陌生,這些技術也顯得不太自然,並且練習題也很費腦子。這很正常,不要被嚇到。如果你被問題卡住,看一下提示和答案,或把問題拋到 Google 用戶組(https://groups.google.com/forum/#!topic/scala-functional/),或 IRC 頻道(#fp-in-scala on irc.freenode.net)。
總之,我們希望這本書對你來說是有趣的、有益的體驗,函數式程式設計能讓你的工作更輕鬆、更愉悅,正如它已經帶給我們的收益。這本書的目的是當你把裡面所有說過的都嘗試過,能幫助你在工作時更有效率。它應該讓你感到不像是在寫一些醜陋、不符合設計原理且難維護的軟體,而更像是要創建一個美觀實用的東西。

序言
編寫好的軟體很難。在各種方法論中糾結多年,我們倆發現並愛上了函數式程式設計(FP)。儘管它與眾不同,但它就是能引領我們編寫出一致連貫、靈活組合、美麗優雅的程式。我們倆都是波士頓地區 Scala 愛好者群(Boston Area Scala Enthusiasts)的成員,這個群會定期在劍橋聚會。起初,群裡主要是一些 Java 程式師,他們一直尋求一些更好的東西。
後來大部分的人都表示,沒有一個好的方法去學習如何用 Scala 進行函數式程式設計。我們學習的過程幾乎都很隨意,寫一些函數式的代碼,向其他 Scala 和 Haskell 程式師請教學習,閱讀一些文章、博客和書籍。我們始終覺得應該有比這更簡單的學習方法,直到 2010 年 4 月,群的組織者之一 Nermin ?erifovi?,建議我們寫一本關於 Scala 函數式程式設計的書。本以為基於我們學習的經驗,寫一本期望中思路清晰的書是一件又快又容易的事情,沒想到我們花
了 4 年多才完成。要是我們當初學習函數式程式設計時,有這樣一本書該多好啊。
希望這本書能夠帶給你一種興奮刺激的感覺, 猶如我們第一次遇到函數式程式設計那樣。

原推薦序
函數式程式設計作為書題出現在 Scala 中是個有趣的現象。畢竟,通常 Scala 被稱為函數式程式設計語言,而且在市場上有非常多的 Scala 相關書籍。是不是這些書都缺失了對語言函數式方面內容的描述?為了回答這個問題,我們需要有指導性地進行深挖。什麼是函數式程式設計?
對我來說,它是“使用函數程式設計”的別名,換句話說,是一種聚焦在函數上的程式設計方式。那麼什麼是函數?再來探尋更大範圍的定義。當一種定義承認函數可能有副作用並返回結果時,純函數式程式設計限制函數就像數學裡定義的那樣:用一種二元關係去映射參數到結果。
Scala 是不純粹的函數式程式設計語言,它同時承認非純粹函數和純函數,而且沒有使用不同的語法或給予不同的類型去區分這兩種函數種類。其他函數式語言也有同樣的屬性。在Scala 裡如果能區分純函數和非純函數將是很好的,但我認為我們沒有找到羽量級的和無需遲疑的靈活方式來這麼做。
可以確信的是,Scala 程式師是被鼓勵使用純函數程式設計的。副作用也有,比如易變、I/O或者異常的使用沒有被禁止,事實上這些副作用有的時候使用起來十分方

目次

目錄
原推薦序
序言
致謝
關於本書
函數式程式設計介紹
1什麼是函數式程式設計

1.1 函數式程式設計的好處:一個簡單的例子
1.1.1 一段帶有副作用的程式
1.1.2 函數式的解法:去除副作用
1.2 (純)函數究竟是什麼
1.3 引用透明、純粹度以及替代模型
1.4 小結
2在Scala中使用函數式程式設計
2.1 Scala語言介紹:
2.2 運行程式
2.3 模組、物件和命名空間
2.4 高階函數:把函數傳給函數
2.4.1 迂回做法:使用迴圈方式
2.4.2 第一個高階函數
2.5 多態函數:基於類型的抽象
2.5.1 一個多態函數的例子
2.5.2 對高階函數傳入匿名函數
2.6 通過類型來實現多態
2.7 小結
3函數式資料結構
3.1 定義函數式資料結構
3.2 模式匹配
3.3 函數式資料結構中的資料共用
3.3.1 資料共用的效率
3.3.2 改進高階函數的類型推導
3.4 基於list的遞迴並泛化為高階函數
3.4.1 更多與清單相關的函數
3.4.2 用簡單元件組合list函數時的效率損失
3.5 樹
3.6 小結
4不是用異常來處理錯誤
4.1 異常的優點與劣勢
4.2 異常的其他選擇
4.3 Option資料類型
4.3.1 Option的使用模式
4.3.2 Option的組合、提升及對面向異常的API的包裝
4.4 Either資料類型
4.5 小結
5嚴格求值和惰性求值

5.1 嚴格和非嚴格函數
5.2 一個擴展例子:惰性列表
5.2.1 對Stream保持記憶,避免重複運算
5.2.2 用於檢測Stream的helper函數
5.3 把函數的描述與求值分離
5.4 無限流與共遞迴
5.5 小結
6純函數式狀態

6.1 以副作用方式生成亂數
6.2 純函數式亂數產生器
6.3 用純函數式實現帶狀態的API
6.4 狀態行為的更好的API
6.4.1 組合狀態行為
6.4.2 嵌套狀態行為
6.5 更通用的狀態行為資料類型
6.6 純函數式命令程式設計
6.7 小結

功能設計和組合子庫
7純函數式的平行計算


7.1 選擇資料類型和函數
7.1.1 一種用於平行計算的資料類型
7.1.2 組合平行計算
7.1.3 顯性分流
7.2 確定表現形式
7.3 完善API
7.4 API與代數
7.4.1 映射法則
7.4.2 分流法則
7.4.3 打破法則:一個微妙的bug
7.4.4 用Actor實現一個完全無阻塞的Par
7.5 完善組合子為更通用的形式
7.6 小結
8基於性質的測試

8.1 基於性質測試概覽
8.2 選擇資料類型和函數
8.2.1 API的初始代碼片段
8.2.2 性質的含義與API
8.2.3 生成器的意義和API
8.2.4 生成值決定生成器
8.2.5 精煉Prop的資料類型
8.3 最小化測試用例
8.4 使用庫並改進其易用性
8.4.1 一些簡單的例子
8.4.2 為平行計算編寫測試套件
8.5 測試高階函數及展望未來
8.6 生成器法則
8.7 小結
9語法分析器組合子
9.1 代數設計,走起
9.2 一種可能的代數
9.2.1 切片和非空重複
9.3 處理上下文的相關性
9.4 寫一個JSON分析器
9.4.1 JSON格式
9.4.2 JSON分析器
9.5 錯誤提示
9.5.1 一種可行的設計
9.5.2 錯誤嵌套
9.5.3 控制分支和回溯軌跡
9.6 實現代數
9.6.1 一種可能的實現
9.6.2 串化分析器
9.6.3 標記分析器
9.6.4 故障轉移和回溯
9.6.5 上下文相關的分析
9.7 小結
函數設計的通用結構
10Monoid


10.1 什麼是monoid
10.2 使用monoid折疊列表
10.3 結合律和並行化
10.4 例子:並行解析
10.5 可折疊資料結構
10.6 組合monoid
10.6.1 組裝更加複雜的monoid
10.6.2 使用組合的monoid融合多個遍歷
10.7 小結 ..151
11Monad
11.1 函子:對map函數的泛化
11.1.1 函子法則
11.2 Monad:對flatMap和unit函數的泛化
11.3 Monadic組合子
11.4 單子定律
11.4.1 結合法則
11.4.2 為指定的monad證明結合法則
11.4.3 單位元法則
11.5 什麼是monad
11.5.1 identity monad
11.5.2 狀態monad和partial type application
11.6 小結
12可應用和可遍歷函子

12.1 泛化單子
12.2 Applicative trait
12.3 單子與可應用函子的區別
12.3.1 對比Option applicative與Option monad
12.3.2 對比Parser applicative與Parser monad
12.4 可應用函子的優勢
12.4.1 不是所有的可應用函子都是Monad
12.5 可應用法則
12.5.1 Left and right identity
12.5.2 結合律
12.5.3 Naturality of product
12.6 可遍歷函子
12.7 使用Traverse
12.7.1 從monoid到可應用函子
12.7.2 帶狀態的遍歷
12.7.3 組合可遍歷結構
12.7.4 遍歷融合
12.7.5 嵌套遍歷
12.7.6 Monad組合
12.8 小結
作用與I/O
13外部作用和I/O


13.1 分解作用13.2 一個簡單的IO類型
13.2.1 處理輸入效果
13.2.2 簡單IO類型的優缺點
13.3 避免棧溢出
13.3.1 將一個控制流轉化為資料構造子
13.3.2 Trampolining:棧溢出的通用解決方法
13.4 一個更微妙的IO類型
13.4.1 合理的monad
13.4.2 一個支持控制台I/O的monad
13.4.3 純解譯器
13.5 非阻塞和非同步I/O
13.6 一個通用的IO類型
13.6.1 最終的main程式
13.7 為什麼IO類型不足以支撐流式I/O
13.8 小結
14本地影響和可變狀態

14.1 純函數式的可變狀態
14.2 一種限制副作用範圍的資料類型
14.2.1 受限可變性的語言表達
14.2.2 一種可變引用的代數表達
14.2.3 執行修改狀態的行為
14.2.4 可變陣列
14.2.5 一個純函數的in-place快排實現
14.3 純粹是相對於上下文的
14.3.1 副作用是什麼?
14.4 小結
15流式處理與增量I/O

15.1 命令式I/O的問題示例
15.2 一個簡單的流轉換器
15.2.1 創建Process
15.2.2 組合和追加處理
15.2.3 處理檔
15.3 可擴展的處理類型
15.3.1 來源
15.3.2 保證資源安全
15.3.3 單一輸入過程
15.3.4 多個輸入流
15.3.5 去向
15.3.6 Effectful通道
15.3.7 動態資源配置
15.4 應用場景
15.5 小結

書摘/試閱

序言
編寫好的軟體很難。在各種方法論中糾結多年,我們倆發現並愛上了函數式程式設計(FP)。儘管它與眾不同,但它就是能引領我們編寫出一致連貫、靈活組合、美麗優雅的程式。我們倆都是波士頓地區 Scala 愛好者群(Boston Area Scala Enthusiasts)的成員,這個群會定期在劍橋聚會。起初,群裡主要是一些 Java 程式師,他們一直尋求一些更好的東西。
後來大部分的人都表示,沒有一個好的方法去學習如何用 Scala 進行函數式程式設計。我們學習的過程幾乎都很隨意,寫一些函數式的代碼,向其他 Scala 和 Haskell 程式師請教學習,閱讀一些文章、博客和書籍。我們始終覺得應該有比這更簡單的學習方法,直到 2010 年 4 月,群的組織者之一 Nermin erifovi,建議我們寫一本關於 Scala 函數式程式設計的書。本以為基於我們學習的經驗,寫一本期望中思路清晰的書是一件又快又容易的事情,沒想到我們花了 4 年多才完成。要是我們當初學習函數式程式設計時,有這樣一本書該多好啊。
希望這本書能夠帶給你一種興奮刺激的感覺, 猶如我們第一次遇到函數式程式設計那樣。

原推薦序
函數式程式設計作為書題出現在 Scala 中是個有趣的現象。畢竟,通常 Scala 被稱為函數式程式設計語言,而且在市場上有非常多的 Scala 相關書籍。是不是這些書都缺失了對語言函數式方面內容的描述?為了回答這個問題,我們需要有指導性地進行深挖。什麼是函數式程式設計?
對我來說,它是“使用函數程式設計”的別名,換句話說,是一種聚焦在函數上的程式設計方式。那麼什麼是函數?再來探尋更大範圍的定義。當一種定義承認函數可能有副作用並返回結果時,純函數式程式設計限制函數就像數學裡定義的那樣:用一種二元關係去映射參數到結果。
Scala 是不純粹的函數式程式設計語言,它同時承認非純粹函數和純函數,而且沒有使用不同的語法或給予不同的類型去區分這兩種函數種類。其他函數式語言也有同樣的屬性。在Scala 裡如果能區分純函數和非純函數將是很好的,但我認為我們沒有找到羽量級的和無需遲疑的靈活方式來這麼做。
可以確信的是,Scala 程式師是被鼓勵使用純函數程式設計的。副作用也有,比如易變、I/O或者異常的使用沒有被禁止,事實上這些副作用有的時候使用起來十分方便, 使用它們的原因有互用性、高效、方便等。但是專家的建議是過度地使用副作用普遍來說不是一種好的方式。然而,因為在 Scala 中非純函數程式設計是可能的甚至是方便的,對命令式程式設計背景的程式師來說,保持他們的風格和不努力採用函數式思維的誘惑就非常大了。事實是,非常有可能將 Scala 編寫成沒有封號結尾的 Java 程式。
那麼要學習 Scala 中的函數式程式設計,是不是需要先學習純函數式程式設計,比如 Haskell ?任何關於方法的爭論都在本書的出現後被極大地削弱了。Paul 和 Rúnar 所做的是簡單地將 Scala 作為純函數式程式設計語言。可變變數、異常、經典的輸入輸出和所有其他的非純函數被消除了。假如你想知道在沒有這些便捷方式下如何編寫有用的代碼,你需要閱讀此書。從第一個原理擴展到增量的輸入輸出,本書展示了如何使用純函數表達每一個概念。而且不僅僅是展示了可能性,也同樣引導你去編寫優美的代碼和深入探索計算的本質。
本書是充滿挑戰的,不僅僅是因為它需要對細節的注意,同樣是對你程式設計思想的挑戰。通過閱讀本書和完成推薦的練習,你將更好地認識純函數式程式設計是什麼,能表達什麼,優點是什麼。
本書讓我特別喜歡的是它的自成體系。它開始於最簡單的運算式,然後從細節解釋每個抽象,再在其基礎上進一步抽象。在某種程度上,本書開發了另一個 Scala“宇宙”,這裡可變狀態是不存在的,所有函數是純的。普遍使用的 Scala 庫的實現和這有些偏離,通常它們是部分按照命令式實現的,(大多數)外層是函數式介面。Scala 容許在函數式介面中封裝可變狀態,我認為這是一個優點。但是這種能力通常也被濫用。假如發現自己過多地使用它,那麼本書是一種強力的解藥。
——MARTIN ODERSKY
Scala 的創造者

推薦序 1
我可能是全中國程式師圈子裡最不適合給《Scala 函數式程式設計》寫序的人。三年前我寫過《Scala 七大死穴》,算是把 Scala 批判了一番。前幾天我則在準備ThoughtWorks 諮詢師大會上的討論話題《沒有函數的函數式程式設計》,又要杯葛函數式程式設計的樣子。
看起來,我無論對 Scala 還是對函數式程式設計,都沒什麼好評嘛。宏江莫不是瘋了,居然要我來寫序?等等,事情似乎不是這樣。最近幾年,ThoughtWorks 的客戶在越來越多的專案中採用了 Scala 技術棧,ThoughtWorks 也孵化出了若干基於 Scalaz 的開源專案。我本人也在這些專案中起到了一些作用。
為什麼我會做這些“口嫌體正直”的事呢?這得從十年前說起。我最早是在 C++ 中開始接觸到函數式程式設計的概念。C++ 和 Scala 一樣,也是一門多範式語言。C++ 的標準庫和 Boost 都提供了許多函數式程式設計的設施。但是,在我職業生涯初期,給我留下深刻印象的函數式程式設計庫要數 Boost.Egg。利用 Boost.Egg,你可以寫出 my_list|filtered(&is_not_X)|filtered(&is_not_Y) 這樣的代碼。你會注意到這種用法和 Scala 標準庫非常相像,它大致相當於 Scala 的 myList.filter(isNotX).filter(isNotY),這種 filter 的用法,本書第 5 章中也有講解。
Boost.Egg 的另一個特點是“非侵入”,比如上例的 filtered 函數,本身並不是 my_list的成員。相反,我們通過重載 | 運算子給原有的類型添加新功能。這種做法在 Scala 裡面相當於隱式轉換,本書第 9 章中提供的例子正是利用隱式轉換,給字串添加了中綴操作符。雖然 Boost.Egg 沒能流行起來,但對我個人而言很重要,因為它很大程度塑造了我對代碼的品位。
有趣的是,Boost.Egg 的作者 Shunsuke Sogame 近年來的開源項目,都是些 Scala 項目,可能這也是因為 C++ 和 Scala 非常相似的緣故吧。
另一個對我代碼品位影響很大的技術是 Lua 中的協程(coroutine)。Lua 的作者Roberto Ierusalimschy 把協程稱為“單趟延續執行流”(One-shot continuation)。有了協程或者延續執行流,程式師可以手動切換執行流,不再需要編寫事件回呼函數,而可以編寫直接命令式風格代碼但不阻塞真正的執行緒。我的前東家網易在開發遊戲時,會大量使用協程來處理業務邏輯,一個遊戲程式內同一時刻會運行成千上萬個協程。
而在其他不支持協程或者延續執行流的語言中,程式師需要非阻塞或非同步程式設計時,就必須採用層層嵌套回呼函數的 CPS(Continuation-Passing Style)風格。 這種風格在邏輯複雜時,會陷入“回檔地獄”(Callback Hell)的陷阱,使得代碼很難讀懂,維護起來很困難。
Scala 語言本身並不支援協程或者延續執行流。因此,一般來說,程式師需要非阻塞或非同步程式設計時,就必須使用類似本書第 13 章“外部作用和 I/O”中介紹的技術,註冊回呼函數或者用 for/yield 語句來執行非同步作業。如果流程很複雜的話,即使是 for/yield 語法仍然會陷入回檔地獄。
我對 Scala 開源社區的貢獻之一是 stateless-future。這個庫提供了一些宏,實現了延續執行流,可以自動把命令式風格的代碼轉換成 CPS 風格。通過這種做法,程式師不再需要手寫本書 13.2 節那樣的代碼了,編寫的代碼風格更像普通的 Java 或者 PHP 風格,直接像流水帳一樣描述順序流程。
後來,我把這種避免回呼函數的思路,推廣到了其他用途上。比如,我開發了基於Scala.js 的前端框架 Binding.scala。使用 Binding.scala 的使用者,編寫普通的 HTML 範本,描述視圖中的變數綁定關係,而不需要編寫高階函數就能做出交互複雜的網頁。
而我的另一個開源庫 Each,則更進一步,支持一切 monad。大多數情況下,使用了Each 就不需要編寫任何高階函數,我稱之為“沒有函數的函數式程式設計”。 這意味,本書第11 章到第 15 章的全部內容,你都可以直接編寫類似 Java 的命令式語法,而 Each 則自動幫你生成使用 monad 的代碼。
總之,我是 Scala 函數式程式設計的死對頭,我寫的 Scala 庫,恰恰是為了避免使用本書中諄諄教導的各種高階函數。如果你是個Java程式師,想在最短的時間內用Scala開始“搬磚”,那麼,從實用角度出發,我建議你合上本書,直接用 Each 即可。因為,雖然 Each 最終會生成 Monad 風格代碼,但是,本書中涉及的使用高階函數的細節,就像組合語言一樣,就算你不知道也照樣可以幹活。
不過,如果你是個求道者,追求程式設計藝術的真理,希望刨根到底,理解函數式程式設計的內在理論和實現機制,那麼本書很適合你。
這本書絕不輕易放過每個知識點,全書包含有大量習題,要求你自己實現 Scala 標準庫或者 Scalaz 中的既有功能。所以,當你讀完本書,做完習題後,雖然你的應用開發能力並不會直接提升,但你會體會到構建函數式語言和框架時的難點和取捨,從而增進你的框架開發和語言設計的能力。
——ThoughtWorks Lead Consultant 楊博

推薦序 2
函數式程式設計與命令式程式設計同樣源遠流長,然而在電腦應用的歷史進程中,二者的地位卻頗不對等。命令式程式設計幾乎自始至終都是大眾的寵兒,函數式程式設計卻長期局限於象牙塔和少數應用領域之內。儘管如此,函數式程式設計的重要性卻從未被忽視,幾十年來生機勃勃地發展,靜靜地等待著逆襲的時刻。事實上,即便是浸淫於命令式程式設計多年的工程師,也常常會與函數式程式設計親密接觸而不自知:例如 SQL、C++ 範本元程式設計,還有 C++ 標準庫中的 STL 等,多少都帶有一些函數式的色彩。早年,受軟硬體水準的限制,函數式語言缺乏高效的編譯器和運行時支援,這可能是函數式語言錯失流行機會的一大原因。近年來,一方面程式語言理論和實現技術突飛猛進,函數式語言在性能上的劣勢越來越不明顯;另一方面,隨著多核、高併發、分散式場景激增,大眾也逐漸開始認識到函數式程式設計在這些領域得天獨厚的優勢。然而,流連於主流命令式語言多年積攢下的庫、框架、社區等豐富資產,再加上長期的教育慣性與思維慣性,使得人們仍然難以在生產上完全轉向函數式語言。
一個新的契機,來自於大資料。社交網路、個人移動設備、物聯網等新技術的興起,使得海量資料處理開始成為家常便飯。人們突然發現,自己在命令式世界的武器庫中,竟找不出稱手的兵器來攻打大數據這座堡壘。2008 年,Google 發表了跨時代的 MapReduce 論文。儘管學界對 MapReduce 頗有非議1 ,MapReduce 的核心思想仍然旋風般席捲了整個工業界,為大資料技術的發展帶來了及時而深遠的影響。有趣的是,MapReduce 的核心思想,正是來自于天生擅長高併發和分散式場景的函數式程式設計。自此以後,各色大資料處理系統層出不窮,而其中的函數式成分也愈加濃重:在使用者介面層面,這些系統往往以 DSL 的形式提供一套類 SQL 語義、具函數式特徵的申明式查詢介面;在實現層面,則仰仗不變性等約束來簡化併發和容錯。然而,出於種種原因,大部分系統的實現語言仍然以 C++、Java、C# 這些命令式語言為主。可謂操命令式之形而施函數式之實。
自 2009 年起,我先後接觸了 Erlang、Scheme、ML 等函數式語言。但出於顯而易見的原因,未能有機會將之用於工程實戰。2013 年春節前後,我參加了由 Scala 之父 Martin Odersky 在Coursera 上開設的 Functional Programming Principles in Scala 課程。湊巧的是,就在課程結束後不久,我便得到一個機會加入 Intel 參與有關大資料和 Apache Spark 的工作。函數式語言和分散式系統一直是我的兩大興趣點,由 Scala 開發的 Spark 恰恰是二者的一個完美融合。
於是,Scala 便成了我的第一門實戰函數式語言。近年來 Spark 的火爆,更是對 Scala 和函數式程式設計的推廣起到了推波助瀾的作用。與我所熟悉的其他函數式語言相比,我想 Scala 最大的優點之一就是過渡平滑。立足於JVM 並將函數式融入如日中天的物件導向,這樣的設計帶來了兩大明顯的好處。第一,順暢地集成了 Java 社區多年積累的財富。第二,Scala 和 C++ 類似,也是一門“廣譜”多範式語言;不熟悉函數式程式設計的 Scala 初學者,隨時可以安全地回退,轉用熟悉的命令式物件導向範式程式設計,從而保證交付速度。這個設計的背後,應該與 Martin Odersky “學術工業兩手抓、兩手都很硬”的風格不無關係。論學術,他師承 Pascal 之父 Niklaus Wirth,在代碼分析和程式語言設計方面建樹頗豐;論工業應用,他一手打造了 Generic Java 和新一代的 javac編譯器。可以說 Martin 既具備了用以高瞻遠矚的理論基礎,又十分瞭解普羅大眾的痛點。
兩相結合,這才造就了 Scala 這樣一個平衡於陽春白雪和下里巴人之間的作品。其實函數式程式設計本身並沒有多難。對於接受過若干年數學訓練,卻沒有任何程式設計經驗的人來說,相較於命令式程式設計中的破壞性賦值,函數式程式設計中的不變性、遞迴等概念反而應該更加親切。譬如中學做證明題時,我們從不會先令 a = x,隔上幾行再令 a = a + 1。真正的困難在於,函數式程式設計中的一些概念和手法——如用尾遞迴代替迴圈——與命令式程式設計的直覺相衝突。對於那些有著多年命令式語言程式設計經驗,把 Java 用得比母語還溜的工程師們而言,一邊要學習新的知識,一邊還要克服多年程式設計訓練所造成的思維定勢,無異於逆水行舟。而在 Scala 中,你永遠有機會在實戰中回退至自己的舒適區。實際上,我們完全可以無視 Scala 的函數式特性,僅僅將 Scala 當作語法更加洗練的 Java。因此,對於那些操持主流命令式物件導向語言多年的工程師們而言,Scala 特別適合用作涉獵函數式程式設計的起步語言。
這本書所講授的,正是基於 Scala 的函數式程式設計基礎。基於 Scheme、Haskell 等老牌函數式語言的傳統教材的問題在於,相關語言的語法和思維方式與讀者現有的知識體系迥異,容易造成較為陡峭的入門門檻。此外,由於這些語言本身的實際應用機會不多,初學者也難以在實戰中獲得寶貴的直覺和經驗。而在 Scala 的幫助下,這本書並不要求你拋開現有的思維方式另起爐灶,它所做的更像是為你現有的思維方式添磚加瓦,從而令你如虎添翼。
最後,作為曾經的譯者,我深知在國內當前的大環境下技術翻譯之不易。每一本優秀技術書籍的中譯本背後都是譯者數月乃至十數月的艱苦付出。感謝諸位譯者為我們帶來又一本好書!
——Spark committer from Databricks 連城

您曾經瀏覽過的商品

購物須知

大陸出版品因裝訂品質及貨運條件與台灣出版品落差甚大,除封面破損、內頁脫落等較嚴重的狀態,其餘商品將正常出貨。

特別提醒:部分書籍附贈之內容(如音頻mp3或影片dvd等)已無實體光碟提供,需以QR CODE 連結至當地網站註冊“並通過驗證程序”,方可下載使用。

無現貨庫存之簡體書,將向海外調貨:
海外有庫存之書籍,等候約45個工作天;
海外無庫存之書籍,平均作業時間約60個工作天,然不保證確定可調到貨,尚請見諒。

為了保護您的權益,「三民網路書店」提供會員七日商品鑑賞期(收到商品為起始日)。

若要辦理退貨,請在商品鑑賞期內寄回,且商品必須是全新狀態與完整包裝(商品、附件、發票、隨貨贈品等)否則恕不接受退貨。

優惠價:87 360
海外經銷商無庫存,到貨日平均30天至45天

暢銷榜

客服中心

收藏

會員專區