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 函式與函數語言程式設計淺析Kotlin函式函數程式設計
- 使用 JavaScript 進行函數語言程式設計 (一)JavaScript函數程式設計
- 從 Redux 原始碼談談函數語言程式設計Redux原始碼函數程式設計
- Kotlin 程式語言初探Kotlin
- javascript函數語言程式設計: 優雅的使用underscore進行函式程式設計JavaScript函數程式設計函式
- Kotlin編寫Processing程式(使用函數語言程式設計思維和麵向介面方式)Kotlin函數程式設計
- Kotlin成為正式的Android程式語言KotlinAndroid
- JavaScript中的函數語言程式設計JavaScript函數程式設計
- JavaScript 中的函數語言程式設計JavaScript函數程式設計
- 函數語言程式設計函數程式設計
- 在Kotlin中如何利用協程進行非同步程式設計Kotlin非同步程式設計
- Scala 函數語言程式設計(一) 什麼是函數語言程式設計?函數程式設計
- 卡馬克:用C++進行函數語言程式設計C++函數程式設計
- 淺談Kotlin中的Sequences原始碼解析(十)Kotlin原始碼
- Android 開發者如何函數語言程式設計 (三)Android函數程式設計
- Spring MVC 函數語言程式設計進階SpringMVC函數程式設計
- Js中函數語言程式設計的理解JS函數程式設計
- Python 中的函數語言程式設計Python函數程式設計
- 函數語言程式設計中的常用技巧函數程式設計
- 函數語言程式設計初嘗之指令碼解析豆瓣首頁函數程式設計指令碼
- 函數語言程式設計,真香函數程式設計
- Java 函數語言程式設計Java函數程式設計
- javascript函數語言程式設計JavaScript函數程式設計
- 初探函數語言程式設計函數程式設計
- 函數語言程式設計初探函數程式設計
- JavaScript 函數語言程式設計JavaScript函數程式設計
- [譯]如何在你的Kotlin程式碼中移除所有的!!(非空斷言)Kotlin
- 【譯】JavaScript 中的函數語言程式設計原理JavaScript函數程式設計
- 函數語言程式設計雜談函數程式設計
- 初見函數語言程式設計函數程式設計
- RAC的函數語言程式設計函數程式設計
- JavaScript 函數語言程式設計(二)JavaScript函數程式設計
- 函數語言程式設計前菜函數程式設計
- JavaScript 函數語言程式設計(一)JavaScript函數程式設計
- JavaScript 函數語言程式設計(三)JavaScript函數程式設計
- python函數語言程式設計Python函數程式設計
- JavaScript函數語言程式設計(二)JavaScript函數程式設計
- JavaScript函數語言程式設計(一)JavaScript函數程式設計