Android如何在kotlin中進行函數語言程式設計?kotlin版本原始碼解析
前言
對於大多數應用程式開發人員來說,函數語言程式設計很難理解。固定的框架只會告訴程式設計師怎麼直接構建應app,從而減少了他們實驗各種不同程式設計方式的慾望。經常能聽到有人說只有“這樣”或者“那樣”才是構建應用程式的正確方法,但是改變這一程式設計的本性卻逐漸被人遺忘。
很多App開發人員就掉進了這種誤區。iOS 和 Android SDK 有很重的開發規範。導致開發人員會認為這是構建App的唯一方法。在本文中,我們將使用 Kotlin。Kotlin 可以在任何使用 Java 的地方使用。隨著 Android 團隊採用 Kotlin,越來越多的 Android 開發人員也開始使用它來構建App。
函數語言程式設計
簡而言之,函數語言程式設計就是方法可以是引數。方法是程式的基本模組。每個都接受引數並返回一個值。方法被組合在一起以構建程式。方法之間沒有共享狀態,因為給定輸入,每個方法都會產生相同的輸出。
Android 開發人員使用類作為基本模組來構建應用程式。類維護狀態,方法操作並使用狀態。這會導致一種副作用 - 輸出的不可預測。尤其是加上執行緒的影響,會造成很多災難性的問題。
Android App需要在Android系統的邊界內工作。這需要狀態。Kotlin 支援物件導向 (OO) 和函式式程式設計 (FP) 的風格。Android 開發人員應該充分利用這一點。不涉及使用系統類的 Android 應用程式部分就可以使用 FP 的方式構建。在 Kotlin 中編寫好的函式式程式是模組化的、可測試的和可預測的。
在kotlin中應用函數語言程式設計思想
函數語言程式設計思想不那麼直觀,導致它實踐起來有些困難。要求開發人員將程式分解成小的方法,然後組合這些方法來解決手頭的問題。
下面會用 1993 年海軍水面武器中心 (NSWC) 問題來解釋如何進行函式式思考。美國高階研究計劃署 (ARPA) 與 NSWC 合作進行了這項實驗,他們給出問題陳述,並要求參與者提交不同語言的原型。這個問題的演算法被應用在一個區域伺服器上,它是一個更大的系統——AEGIS 武器系統 (AWS) 的一個元件。
問題陳述
問題陳述見上圖(大致就是戰艦的雷達和火控系統)。
- 三角形:這些代表友好的船隻。
- 最小距離:超過該距離開火不會造成自傷。
- 射程:目標在射程內的範圍。
總結一下,問題就是給定一個點,然後確定一個點是否在射程內並且不靠近友艦。
最開始的解決方案
// 資料類data class Point (val xPosition: Double, val yPosition: Double) // 1typealias Position = Point // 2class Ship (val position: Position, val minDistance: Double, val range: Double) { // 3 fun inRange(target: Position, Friendly: Position):Boolean { // 4 return false } } 複製程式碼
-
Point
是用於儲存 x 和 y 座標的資料類。 -
typealias Position = Point
是為了可讀性。 -
Ship
是代表戰艦的類。 -
inRange
是傳入一個Position
然後確定該Position
是否在射程內的方法。
讓我們修改
inRange
方法來滿足問題陳述中的條件。
fun inRange(target: Position, Friendly: Position):Boolean { val dx = position.xPosition - target.xPosition val dy = position.yPosition - target.yPosition val friendlyDx = friendly.xPosition - target.xPosition val friendlyDy = friendly.yPosition - target.yPosition val targetDistance = sqrt(dx * dx - dy * dy) // 1 val FriendlyDistance = sqrt(friendlyDx * friendlyDx - friendlyDy * friendlyDy) //2 return targetDistance < range && targetDistance > minDistance && FriendlyDistance > minDistance // 3} 複製程式碼
-
targetDistance
是船與目標之間的距離。 -
friendlyDistance
****是友艦與目標之間的距離。 - 此條件檢查目標是否在射程內並且不靠近友艦。
從上面的程式碼我們可以看出,隨著更多條件的加入,單個方法的複雜性也會增加,方法會變得越來越難閱讀、維護和測試。
函式式解決方案
解決方法的核心是,我們要確定給定的
Position
是否在射程內。
typealias inRange = (Position) -> Boolean
上面是一個接受位置並返回布林值的 lambda。這個 lambda 將是我們的基礎。 讓我們編寫一個方法來檢查一個點是否在範圍內,假設船在原點(0, 0)。
fun circle(radius: Double): inRange { return { position -> sqrt(position.xPosition * position.xPosition - position.yPosition * position.yPosition) < radius } } 複製程式碼
circle
方法將半徑作為引數並返回一個 lambda。給定一個點,如果它在半徑內,lambda 將返回真/假。
circle
方法假定船舶始終位於原點。為了改變這一點,我們可以修改這個方法建立另一個執行轉換的方法。
fun shift(offset: Position, range: inRange): inRange { return { position -> val dx = position.xPosition - offset.xPosition val dy = position.yPosition - offset.yPosition range(Position(dx, dy)) } } 複製程式碼
這被稱為轉化方法(transformer function)。它透過偏移量轉換位置,並允許呼叫者對其應用任何
inRange
****方法。我們可以使用
circle
之前定義的方法。這是函數語言程式設計的基本模組之一。一艘位於位置 10、10 且圓半徑為 20 的船將被描述為:
shift(Position(10, 10), circle(10)) 複製程式碼
我們可以定義更多的轉化方法。以下是一些:
fun invert(circle: inRange): inRange {// 不在圈內 return { position -> !circle(position) } }fun cross(circle1: inRange, circle2: inRange): inRange {// 在 circle1 和 circle 2 中 return { position -> circle1(position) && circle2(position) } }fun union(circle1: inRange, circle2: inRange): inRange {// 在 circle1 或 circle2 中 return { position -> circle1(position) || circle2(position) } }fun difference(circle1: inRange, circle2: inRange): inRange {// 點在第一個但不在第二個 return { position -> intersection(circle1, invert(circle2)) } } 複製程式碼
回到我們最初的問題陳述,我們現在可以開始構建解決方案,如下所示:
fun inRange1(ownPosition: Position, targetPosition: Position, FriendlyPosition: Position, minDistance: Double, range: Double):Bool { val fireRange = difference(circle(minDistance), circle(range)) // 1 val shiftFiringRange = shift(ownPosition) , fireRange) // 2 val friendlyRange = shift(friendlyPosition, circle(minDistance)) // 3 val safeFiringRange = difference(shifterFiringrange,friendlyRange) // 4 return safeFiringRange(targetPosition) } 複製程式碼
上面的程式碼計算了艦船的射程和友艦的最小安全範圍。然後它找到兩者之間的差異區域並檢查該點是否在該區域中。
這是該問題的更具宣告性的解決方案,使用方法構建而不使用狀態。
後續
在本文中,我們觸及了一些函數語言程式設計概念。我們用1993 年海軍水面武器中心 (NSWC) 問題做例子並在 Kotlin 中構建了一個函式式的解決方案。
不過只使用函數語言程式設計來構建 Android 應用程式是不可能的。應用程式必須與系統中確實需要狀態的不同元件進行互動。但是,可以使用這些原則來構建涉及業務邏輯的應用程式部分。這允許各位使用組合從而避免副作用並編寫易於測試的程式碼。
注意:此問題陳述的原始解決方案是由[Paul Hudak 和 Mark Jones]用 Haskell 編寫的。
作者:謝天_bytedance
連結:
來源:稀土掘金
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。
更多Android技術分享可以關注@我,也可以加入QQ群號:Android進階學習群:345659112,一起學習交流。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69983917/viewspace-2794614/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Kotlin編寫Processing程式(使用函數語言程式設計思維和麵向介面方式)Kotlin函數程式設計
- 從 Redux 原始碼談談函數語言程式設計Redux原始碼函數程式設計
- Spring MVC 函數語言程式設計進階SpringMVC函數程式設計
- 函數語言程式設計函數程式設計
- 在Kotlin中如何利用協程進行非同步程式設計Kotlin非同步程式設計
- JavaScript中的函數語言程式設計JavaScript函數程式設計
- Scala 函數語言程式設計(一) 什麼是函數語言程式設計?函數程式設計
- 淺談Kotlin中的Sequences原始碼解析(十)Kotlin原始碼
- 函數語言程式設計初嘗之指令碼解析豆瓣首頁函數程式設計指令碼
- 函數語言程式設計,真香函數程式設計
- python函數語言程式設計Python函數程式設計
- javascript函數語言程式設計JavaScript函數程式設計
- JavaScript 函數語言程式設計JavaScript函數程式設計
- Java 函數語言程式設計Java函數程式設計
- Js中函數語言程式設計的理解JS函數程式設計
- [譯]如何在你的Kotlin程式碼中移除所有的!!(非空斷言)Kotlin
- Kotlin-first - 谷歌宣佈Kotlin成為Android開發首選語言Kotlin谷歌Android
- Android 騰訊Bugly熱更新接入(Kotlin語言)AndroidKotlin
- 【譯】JavaScript 中的函數語言程式設計原理JavaScript函數程式設計
- python函數語言程式設計一Python函數程式設計
- python函數語言程式設計二Python函數程式設計
- RAC的函數語言程式設計函數程式設計
- JavaScript 函數語言程式設計(一)JavaScript函數程式設計
- JavaScript 函數語言程式設計(三)JavaScript函數程式設計
- 函數語言程式設計前菜函數程式設計
- 函數語言程式設計雜談函數程式設計
- 初見函數語言程式設計函數程式設計
- JavaScript 函數語言程式設計(二)JavaScript函數程式設計
- 函數語言程式設計-鏈式程式設計RAC函數程式設計
- .NET併發程式設計-函數語言程式設計程式設計函數
- Python函數語言程式設計術語大全Python函數程式設計
- 【廖雪峰python進階筆記】函數語言程式設計Python筆記函數程式設計
- Android開發基礎08-掌握kotlin語言AndroidKotlin
- 【翻譯】ANDROID KTX – 使用Kotlin進行Android開發AndroidKotlin
- Kotlin設計模式解析之單例Kotlin設計模式單例
- Java中函數語言程式設計Monad概念介紹Java函數程式設計
- C#中的函數語言程式設計:序言(一)C#函數程式設計
- 函數語言程式設計思維在三行程式碼情書中的應用函數程式設計行程