本日內容取自 Kotlin Conf 2023 - Kotlin & Functional Programming: pick the best, skip the rest by Urs Peter這個影片,裡面講到如何從指令式程式設計 (Imperative programming) 到利用 scope funtion 達到表達式程式設計最後再到 functional programming,對於 Monad 解釋也很清楚,是個非常好的影片,推薦大家去看
如果是告訴電腦如何一步一步的執行,我們會稱為指令式程式設計,程式碼是說明如何作 (How to do)。如此的程式碼有比較大的機會使用可變變數,可變集合,較長的變數範圍,在許多地方 return , 這些都違反我們前幾天說的原則,如以下程式碼:
fun devsToFile(fileName: String): Result {
val client RestClient()
client.username = "reader"
client.secret = System.getenv("pwd")
client.url="https://..."
client.initAccessToken()
try{
//檔案處理
val file File(fileName)
file.createNewFile()
file.setWritable(true)
//取得外部資料
val devs = client.getAll<Developer>()
require (devs.isNotEmpty()) {
val msg = "No devs found"
LOG.error(msg)
msg
}
//列印到檔案
devs.forEach(file.appendText(it.toCSV())}
return Result (devs. size, file.length())
}
finally {
client.close()
}
}
以上的例子其實有點故意,是我應該還是會先確定取得外部資料再來開 FileStream.但因為沒有 scope function 比較難限制開發者跳來跳去的思維
那如果利用Kotlin 的 scope function ,就可限制變數的範圍(scope)並讓流程更易讀,這個就會稱為表達式程式設計,改寫如下例
fun devsToFile(fileName: String): Result =
//利用 apply 限縮可變空間
RestClient().apply{
username = "reader"
secret = System.getenv("pwd")
url = "https://..."
initAccessToken()
}.use { client -> //使用 use 在結束自動 close
client.getAll-Developer>().let { devs ->
require(devs.isNotEmpty()) {
"No devs found".also { LOG.error(it) }
}
File(fileName).run {
createNewFile()
setWritable(true)
devs.forEach(appendText (it.toCSV())}
Result(devs.size, length())
}
}
}
我們利用了幾個 Kotlin Scope function
我們再把改造前後的程式放在一起比較,左邊的看起來比較容易閱讀並且安全呢!
當我們想改變想的是轉成 CSV 的格式。例如文字要不要加上 ""。我們可以把 (Developer)->String
抽成函數參數,而能接受函數參數的函數叫作 High-order function, 如下我們把
(Developer)->String 變成參數傳入。這個 function 就更有彈性能夠複用
fun devsToFile(fileName: String, toLine:(Developer) -> String ): Result =
//利用 apply 限縮可變空間
RestClient().apply{
username = "reader"
secret = System.getenv("pwd")
url = "https://..."
initAccessToken()
}.use { client -> //使用 use 在結束自動 close
client.getAll-Developer>().let { devs ->
require(devs.isNotEmpty()) {
"No devs found".also { LOG.error(it) }
}
File(fileName).run {
createNewFile()
setWritable(true)
devs.forEach(appendText (toLine(it))}
Result(devs.size, length())
}
}
}
今天來推這首美式校園風的 Allergy