1. 程式人生 > >Monad新解-FRP對比——ReactiveCocoa、RxSwift、Bacon以及背後的Functional

Monad新解-FRP對比——ReactiveCocoa、RxSwift、Bacon以及背後的Functional

ReactiveX

Rx的Observable的本質就是一個Event Monad,即上下文(就是圖文教程中包裹的盒子)為Event的一個Monad,這裡的Event定義,可以對應語言的struct或者enum,包括了next、error和complete三個上下文即可。這裡擷取的是Swift語言的實現,map方法實現拆裝箱(類似Optional,即Haskell的Maybe)

public enum Event<Element> {

    /// Next element is produced.

    case next(Element)

 

 

    /// Sequence terminated with an error.

    case error(Swift.Error)

 

 

    /// Sequence completed successfully.

    case completed

}

 

 

extension Event {

    /// Maps sequence elements using transform. If error happens during the transform .error

    /// will be returned as value

    public func map<Result>(_ transform: (Element) throws -> Result) -> Event<Result> {

        do {

            switch self {

            case let

.next(element):

                return .next(try transform(element))

            case let .error(error):

                return .error(error)

            case .completed:

                return .completed

            }

        }

        catch let e {

            return .error(e)

        }

    }

}

 

 

而Rx的subscribe方法就是一個解包,也就是Monad<Event>.map(),接收一個(Event) -> void的引數。或者使用更一般直觀的三個引數onNext: (Element) -> Void、onError: (Error) -> Void、onCompleted: (Void) -> Void方法(在其他語言實踐上,RxJS就是三個function引數,而RxJava為了支援Java7可以使用匿名內部類)

理論:

Monad Event <$> subscribe

 

示例:

let subscription = Observable<Int>.interval(0.3)

.subscribe { event in

print(event) // unwraped event

}

 

 

let cancel = searchWikipedia("me")

.subscribe(onNext: { results in

print(results)

}, onError: { error in

print(error)

})

 

 

Rx的Operator是Functor,也就是說(Event) -> Event,因此可以通過Monad不斷bind你想要的組合子,直到最終符合UI控制元件需要的資料

理論:

Monad Event >>= map >>= concat >>= filter >>= map <$> subscribe

 

示例:

let subscription = primeTextField.rx.text           // Observable<String>

.map { WolframAlphaIsPrime(Int($0) ?? 0) }      // Observable<Observable<Prime>>

.concat()                                       // Observable<Prime>

.filter { $0.isPrime }                          // Observable<Prime>

.map { $0.intValue }                            // Observable<Int>

 

Promise / Future

Promise本質上也是一個Monad,包裹的上下文就是resolve和reject。

你可能反駁說Promise.then(f)中的f,可以是value => value,而並不是一個被Promise包裹的型別啊。但是實際上,由於JavaScript型別的動態性,Promise.then中直接返回value型別是個語法糖罷了,實際上會處理為value => Promise.resolve(value)

Promise.resolve(1)

.then(v => v+1) //便捷寫法罷了,返回的是resolved狀態的Promise物件

.then(v => Promise.resolve(v+1)) //完整寫法

.then(v => Promise.reject('error ' + v)) //想要返回rejected狀態,無便捷方法

.catch(e => console.log(e)) // error 3

 

原理:

Monad Promise >>= then >>= then >>= catch >>= then

示例:

Promise.resolve(1)

  .then(v => {

    return v + 1; // 1

  }.then(v =>  {

    throw new Error('error'); //reject

  }.catch(e => {

    console.log(e); // error

    return Promise.resolve(0);

  }.then(v => {

    console.log('end', v); // end 0

  }

 

https://dreampiggy.com/2016/11/17/FRP簡介—ReactiveCocoa、RxSwift、Bacon以及背後的Functional/