Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Functional Reactive Programming

Functional Reactive Programming

halfrost

June 15, 2017
Tweet

More Decks by halfrost

Other Decks in Programming

Transcript

  1. FRP & RAC
    冰霜

    View full-size slide

  2. 什么是函数响应式?

    View full-size slide

  3. 命令式 VS 函数式
    int factorial(int x){
    if (x < 0)
    return INT_MIN;
    int result = 1;
    for (int i = 1; i <= x ; ++i) {
    result *= i;
    }
    return result;
    }
    1. 如何计算
    2. 表达式和语句
    3. 状态量
    函数式编程⾥⾯是基本上没有状态量,只有表达式,也没有赋值语句。利⽤了递归解决了问题。
    int factorial(int x){
    if (x < 0)
    return INT_MIN;
    if (x==1) return 1;
    return x * factorial(x-1);
    }

    View full-size slide

  4. 命令式 VS 响应式
    09:30
    Magna

    Amet
    05:20 AM
    09:45 PM
    Euismod, Ipsum
    void react() {
    int a = 8;
    int b = 9;
    int c = a + b;
    a = 10;
    NSLog(@"%d", c);
    }
    在⾯向对象语⾔中也是可以实现响应式编程的,具体做法应该是,把关系抽象出来,然后把
    变化抽象出来,⽤关系把变化事件传递下去。Cocoa框架下RAC的实现就是如此。

    View full-size slide

  5. Cum sociis
    natoque
    penatibus et
    magnis
    parturient
    montes.
    在计算机编程中,假如满⾜下⾯这两
    个句⼦的约束,⼀个函数可能被描述
    为⼀个纯函数:
    1. 给出同样的参数值,该函数总是
    求出同样的结果。该函数结果值不
    依赖任何隐藏信息或程序执⾏处理
    可能改变的状态或在程序的两个不
    同的执⾏,也不能依赖来⾃I/O装置
    的任何外部的输⼊(通常是这样的
    --看下⾯的描述)。
    2. 结果的求值不会促使任何可语义
    上可观察的副作⽤或输出,例如易
    变对象的变化或输出到I/O装置。
    纯函数 函数的返回值是不需要依赖所有(或任
    何)参数值,必须不依赖参数值以外的
    东⻄。函数可能返回多重结果值,并且
    对于被认为是纯函数的函数,这些条件
    必须应⽤到所有返回值。假如⼀个参数通
    过引⽤调⽤,任何内部参数变化将改变函
    数外部的输⼊参数值,它将使函数变为⾮
    纯函数。
    ⼀个纯函数在执⾏的过程中,只跟
    ⼊参有关,在函数体中并不会引⽤
    外部全局变量,或者说是⼀个类⽅
    法⾥⾯的其他成员变量。另外,纯
    函数除了返回值之外,也不会去改
    变外部的变量值。满⾜上⾯这两点
    的纯函数,就可以说它是引⽤透明
    的。也有说法叫这种特性为幂等性

    View full-size slide

  6. 副作⽤
    ⼀等函数的理念可以追溯到 Church 的 lambda 演算 (Church 1941; Barendregt 1984)。此后,包括 Haskell,OCaml,Standard
    ML,Scala 和 F# 在内的⼤量 (函数式) 编程语⾔都不同程度地借鉴了这个概念。
    PS:世界上最纯粹的函数式编程语⾔⾮Haskell莫属。
    函数式编程强调没有"副作⽤",意味着函数要保持
    独⽴,所有功能就是返回⼀个新的值,没有其他⾏
    为,尤其是不得修改外部变量的值。

    View full-size slide

  7. 函数式编程Functional Programming
    1. 函数是"第⼀等公⺠"
    2. 闭包和⾼阶函数
    3. 不改变状态
    4. 递归
    5. 只⽤"表达式",不⽤"语句",没有副作⽤
    85% 50% 76% 95%
    Functional Programming is a programming
    paradigm
    1. treats computation as the evaluation of
    mathematical functions.
    2. avoids changing-state and mutable data
    所谓"第⼀等公⺠"(first class),指的是函数与其他数据类型⼀样,处于平等地位,可以赋值给其他变量,也可
    以作为参数,传⼊另⼀个函数,或者作为别的函数的返回值。

    View full-size slide

  8. 函数响应式编程FUNCTIONAL REACTIVE PROGRAMMING
    函数响应式编程是⾯向离散事件流的,在⼀个时间轴上会产⽣
    ⼀些离散事件,这些事件会依次向下传递。
    RAC就是Cocoa框架下的函数响应式编程的实现。它提供了基
    于时间变化的数据流的组合和变化。
    明⽩了!

    View full-size slide

  9. ⾯向对象编程
    Object Oriented Programming
    响应式编程
    Reactive Programming
    函数式编程 Functional Programming
    函数响应式编程
    Functional Reactive Programming

    View full-size slide

  10. Tortor Sem Dapibus

    View full-size slide

  11. Tortor Sem Dapibus

    View full-size slide

  12. Github Mac 客户端附产物
    01
    FRP在Cocoa框架下的实现
    02
    富含了Cocoa框架下的多种组

    03
    提供了基于时间变化的数据流
    的组合和变换的操作
    04
    简称 RAC
    05
    什么是 ReactiveCoCoa ?

    View full-size slide

  13. Reactive Objc

    View full-size slide

  14. RACSequence VS RACSignal
    Pull-Driver
    Data
    Push-Driver
    Event

    View full-size slide

  15. RACDisposable
    RACScheduler
    RACCommand
    RACSubscriber

    View full-size slide

  16. RAC 基础
    RACSignal *signal = [RACSignal createSignal:
    ^RACDisposable *(id subscriber)
    {
    [subscriber sendNext:@1];
    [subscriber sendNext:@2];
    [subscriber sendNext:@3];
    [subscriber sendCompleted];
    return [RACDisposable disposableWithBlock:^{
    NSLog(@"signal dispose");
    }];
    }];
    RACDisposable *disposable = [signal subscribeNext:^(id x) {
    NSLog(@"subscribe value = %@", x);
    } error:^(NSError *error) {
    NSLog(@"error: %@", error);
    } completed:^{
    NSLog(@"completed");
    }];
    [disposable dispose];

    View full-size slide

  17. 单个信号的变换
    RACSignal 的各类操作

    View full-size slide

  18. 85% 50% 76% 95%
    数量操作
    RACSignal 的各类操作

    View full-size slide

  19. RACSignal
    Repeat 操作
    Signal A ——‘AA’——‘BB’—|—————————
    Signal B ——‘AA’——‘BB’———‘AA’——‘BB’———‘AA’——‘BB’—

    View full-size slide

  20. 时间操作
    RACSignal 的各类操作

    View full-size slide

  21. RACSignal
    + (RACSignal *)interval:(NSTimeInterval)interval
    onScheduler:(RACScheduler *)scheduler;

    View full-size slide

  22. RACSignal
    如何得到⼀个每隔⼀秒延迟发送⼀个值的⽆限信号?
    (假设每个值都是1,即[RACSignal return:@1])
    RACSignal *interval = [[[RACSignal return:@1] delay:1] repeat];
    如何把下⾯这个信号每个值中间都插⼊1秒的时间间隔?
    RACSignal *signal = @[@1, @3, @7, @9, @8].rac_sequence.signal;
    RACSignal *timerSignal = [[signal map:^id(id value) {
    return [[RACSignal return:value] delay:1];
    }] concat];

    View full-size slide

  23. 多个信号的组合
    RACSignal 的各类操作

    View full-size slide

  24. ANSWER
    1. RAC 在哪些场景下可以提⾼开发效率?
    可否举个最明显的例⼦。

    2. RAC 有哪些缺陷?⽐如RAC的哪些操作
    执⾏效率⽐较低?

    3. 如何降低新同事的学习成本?即有⽊有
    快速⼊⻔的系列教程可以推荐,适合⼊
    ⻔的,中级的,深⼊的。

    4. ReactiveCocoa 和 ReactiveSwift 啥关
    系?
    ⼊⻔资料官⽅⽂档
    基础⽤法都要熟悉
    先回答第三题
    中级
    多实践,思维的转变,⽤函数式
    去思考问题
    深⼊
    看源码,了解底层实现,领悟
    RAC的精髓。如何不⽤RAC实现
    MVVM中的绑定操作?bind 和
    Monad 范畴论

    View full-size slide

  25. 2 3
    1
    RAC适合的场景
    事件处理 切⾯处理
    异步场景

    View full-size slide

  26. 处理成功的回调
    01
    处理异常和错误
    02
    ⽀持取消操作
    03
    subscribenext
    01
    subscribeError
    02
    disposable
    03
    异步处理
    还能有效解决回调地狱的问题 PromiseKit
    (PromiseKit 是 RAC的 Continuation-Passing Style)

    View full-size slide

  27. 异步处理
    信号的降阶
    和升阶
    错误传递和
    捕获的统⼀
    信号的组合
    与变换
    线程操作RACScheduler⽅便
    01 02 03

    View full-size slide

  28. UI事件
    事件处理
    Delegate
    RAC对整个UIKit库都有对应的
    Category

    View full-size slide

  29. 切⾯处理
    KVO
    ⽅法调⽤与监听

    View full-size slide

  30. 同步场景
    14% 68% 47%
    RAC不适合的场景
    纯OOP场景 缺陷
    调试困难
    对新⼿不友好
    学习曲线陡峭

    View full-size slide

  31. 09:30
    Magna

    Amet
    05:20 AM
    09:45 PM
    Euismod, Ipsum
    ReactiveSwift 是 RAC 在 Swift 语⾔出来以后针对 Swift
    的实现。
    ReactiveSwift ⾥⾯没有冷信号。全是热信号。
    ReactiveSwif
    在ReactiveCocoa v2.5中,flatten默认就是flattenMap:这
    ⼀种操作。
    ReactiveCocoa v3.x,v4.x,v5.x中,flatten的操作是可以
    选择3种操作选择的。merge,concat,switchToLatest。
    ReactiveCocoa 和 ReactiveSwift

    View full-size slide

  32. ANSWER
    1. RAC 和 Rx 对⽐

    2. MVVM 实践探讨,哪⾥该⽤哪⾥不该⽤

    3. 双向绑定 vs 单向绑定

    4. 如何将事件传递流暴露的更明显,⽽不是
    像 notify ⼀样分散
    1.RAC 和 Rx 都是采⽤ FRP 思想
    实现的⼀个库。RAC有OC版
    本,Rx只有Swift版本。Rx家族
    API特别⼀致。
    第⼆题请⽼⼤回答
    3.双向绑定:

    当⼀个⼦组件改变了⼀个prop的值
    时,这个变化也会同步到⽗组件中所
    绑定的值。但也会导致问题。由于⼦
    组件改变prop的代码和普通的状态改
    变代码毫⽆差别,当光看⼦组件的代
    码时,你完全不知道它何时悄悄地改
    变了⽗组件的状态。这在debug复杂
    结构的应⽤时会带来很⾼的维护成
    本。
    4.⽤⼀个消息中⼼或者消息总线来处理

    View full-size slide