Swift 函數(shù)式編程探索(3)—— Applicative 和 Curry

前兩篇說了 monad 和 functor ,這兩個算是比較經(jīng)常會實際使用的。
這里說的兩個函數(shù)式編程 Feature ,相對就沒有那么廣泛的使用了。
Applicative 和 Curry ,其中 applicative 并沒有在 swift 中原生集成(雖然實現(xiàn)起來也很容易), Curry 在 swift 3.0 中被移除了(雖然自己實現(xiàn)起來還是很容易)。
這里用到的代碼我都寫在了 playground 里,放到了 Github

這里簡單說一下吧。

1. Applicative

只要實現(xiàn)了 Apply 函數(shù)如何作用于自身,就是一個 Applivative。

Optional 的 Apply

我們可以這樣對 optional 和 SequenceType 擴充一個 apply 方法:

extension Optional {
    func apply<T>(f: (Wrapped -> T)?) -> T? {
        if let f = f {
            return self.map(f)
        }
        return nil
    }
}

這樣 Optional 就是一個 Applivative 了,我們可以這樣來使用:

let b = Optional.Some(1)
let a = Optional.Some({ $0 + 1 })
b.apply(a)  // 返回 Optional(2)
SequenceType 的 Apply

我們同樣可以對 SequenceType 擴充一個 apply 方法

extension SequenceType {
    func apply<T>(fs: [Generator.Element -> T]) -> [T] {
        var result = [T]()
        for f in fs {
            for element in self.map(f) {
                result.append(element)
            }
        }
        return result
    }
}

這樣一來 SequenceType 也是 Applicative 了。
我們可以怎么使用呢?

let plusTwoAndThree = [ { $0 * 2 }, { $0 * 3 } ]
let ints = [1, 2, 3]
ints.apply(plusTwoAndThree)  // 返回 [2, 4, 6, 3, 6, 9]
實踐

和 functor 和 monad 類似,我們定義一個操作符 <*>

infix operator <*> { associativity left }

func <*><U, T>(f: (U -> T)?, a: U?) -> T? {
    return a.apply(f)
}

func <*><S: SequenceType, T>(f: [S.Generator.Element -> T], a: S) -> [T] {
    return a.apply(f)
}

然后我們就可以這樣:

a <*> b
plusTwoAndThree <*> ints

2. Curry

簡單地來說,Curry 就是一個生成方法的方法
比如說這里:

func operate(num: Int) -> (Int -> Int) -> Int {
    return {
        operate in operate(num)
    }
}

這是一個接收一個 Int 參數(shù),返回一個接受一個 Int -> Int 參數(shù)的方法,再返回 Int
這么說可能有點繞,比如我們使用這個方法:

let operateOne = operate(1)  // (Int -> Int) -> Int

這里的 operateOne 就是一個生成的方法,它接受一個 Int -> Int 方法,然后返回 Int
我們可以拿這個 operateOne 這么使用:

let addOne: Int -> Int = { $0 + 1 }
let addTwo: Int -> Int = { $0 + 2 }

operateOne(addOne)  // 返回2
operateOne(addTwo)  // 返回3

使用 curry 能夠量產(chǎn)方法,可以避免寫一些重復(fù)的代碼。

實踐

在 swift 3.0 中,已經(jīng)把 curry 函數(shù)移除了,詳情可以見這里:
remove-currying

  // Before:
  func curried(x: Int)(y: String) -> Float {
    return Float(x) + Float(y)!
  }

像這種已經(jīng)不能寫了,但是可以用這種方法,也能輕易實現(xiàn):

  // After:
  func curried(x: Int) -> (String) -> Float {
    return {(y: String) -> Float in
      return Float(x) + Float(y)!
    }
  }

但是我們不是都有機會去修改代碼的,比如說一些第三方庫什么的,我們可以用這樣的泛型函數(shù)生成一個柯里函數(shù):

func curry<A,B,R>(fun: (A,B) -> R) -> A -> B -> R {
    return { a in { b in fun(a,b) } }
}

這么使用:

func operate(num: Int, f: Int -> Int) -> Int {
    return f(num)
}

let curryOperate = curry(operate)

curryOperate(1)(addOne)  // 返回 2

curry 和 applicative 也是函數(shù)式編程的重要部分,但是相對于 map 和 flatMap ,并沒有在 swift 中那么多的使用,但是掌握了它們,仍然能為我們帶來更好的開發(fā)思維,具體可以如何使用呢?
可以看一看我的這一篇:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容