Kotlin強行模擬Point-Free
原文保留完整格式
昨天在學習Haskell的過程中了解了什麼是Point-Free風格,然後瞬間中毒。於是我就打算在Kotlin裡面模擬一下。
這是Haskell中不Point-Free的版本:
generate :: (Num a, Enum a) => [a] -> [a]n-- not point freengenerate ls = zipWith (*) [0..] lsn
引用大魔頭在他的Haskell教程裡面說過的一句話,
兩邊約掉個參數
於是我們可以寫出Point-Free的版本:
generate :: (Num a, Enum a) => [a] -> [a]n-- point freengenerate = zipWith (*) [0..]n
然後我就嘗試把它翻譯為Kotlin。
解釋
首先向各位看不懂Haskell的看官解釋一下什麼是Point-Free。
柯里化
先假設Kotlin自帶柯里化,也就是說,我定義函數
fun a(a: Int,b: Int) = a + bn
之後,我可以這樣調用
val x = a(1)nval y = x(2)nprint(y) // 3n
Point-Free
然後我可以這樣:
fun plus1(x: Int) = a(1)(x)n
對吧,就是一個返回參數+ 1的函數。
這是不Point-Free的寫法。
fun plus1() = a(1)n
這是Point-Free的寫法。很簡單吧。
Kotlin強行模仿
因為標準庫沒有zipWith這個函數,所以我們先寫一個,然後手動柯里化了:
fun <A, B, C : Any> zipWith(op: (A, B) -> C) = { x: Sequence<A> ->n { y: Sequence<B> ->n val iX = x.iterator()n val iY = y.iterator()n generateSequence {n if (iX.hasNext() and iY.hasNext()) op(iX.next(), iY.next())n else nulln }n }n}n
此處使用了惰性序列Sequence來模擬Haskell的惰性求值,然後使用返回帶參數的Lambda的方式模擬柯里化。
然後寫個那個破函數:
fun generate() = zipWith { x: Int, y: Int -> x * y } (n generateSequence(0, Int::inc)n)n
對比Haskell的兩行:
generate :: (Num a, Enum a) => [a] -> [a]ngenerate = zipWith (*) [0..]n
很簡單吧?調用就是這樣:
fun main(args: Array<String>) {n generate()(sequenceOf(1, 1, 2, 3, 5, 8, 13, 21))n // .forEach(::println)n}n
把那行注釋取消了就是輸出。
對比Haskell的調用:
generate [1, 1, 2, 3, 5, 8, 13, 21]n
Easy~
完整的代碼
我把完整的代碼貼到了我的gist上。
試下調用gist的API(很可能需要翻牆才能看到)(很可惜知乎不支持這格式):
package mainnn/**n * Created by ice1000 on 2017/4/27.n *n * @author ice1000n */nnfun <A, B, C : Any> zipWith(op: (A, B) -> C) = { x: Sequence<A> ->nt{ y: Sequence<B> ->nttval iX = x.iterator()nttval iY = y.iterator()nttgenerateSequence {ntttif (iX.hasNext() and iY.hasNext()) op(iX.next(), iY.next())ntttelse nullntt}nt}n}nnfun <T : Any> generate() = {ntzipWith { x: Int, y: T -> "[$y * x^$x]" }(ntttgenerateSequence(0, Int::inc)nt)n}nnfun main(args: Array<String>) =nttgenerate<Int>()()(sequenceOf(1, 1, 2, 3, 5, 8, 13, 21))ntttt.forEach(::println)nn// view rawpoint-free.kt hosted with ? by GitHubn
推薦閱讀:
※GHC API 系列筆記(1):入門篇
※仙境里的Haskell(之二)
※Equational Reasoning的含義是什麼?