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. 命令式 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); }
  2. 命令式 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的实现就是如此。
  3. Cum sociis natoque penatibus et magnis parturient montes. 在计算机编程中,假如满⾜下⾯这两 个句⼦的约束,⼀个函数可能被描述

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

    Haskell,OCaml,Standard ML,Scala 和 F# 在内的⼤量 (函数式) 编程语⾔都不同程度地借鉴了这个概念。 PS:世界上最纯粹的函数式编程语⾔⾮Haskell莫属。 函数式编程强调没有"副作⽤",意味着函数要保持 独⽴,所有功能就是返回⼀个新的值,没有其他⾏ 为,尤其是不得修改外部变量的值。
  5. 函数式编程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),指的是函数与其他数据类型⼀样,处于平等地位,可以赋值给其他变量,也可 以作为参数,传⼊另⼀个函数,或者作为别的函数的返回值。
  6. RAC 基础 RACSignal *signal = [RACSignal createSignal: ^RACDisposable *(id<RACSubscriber> 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];
  7. 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];
  8. ANSWER 1. RAC 在哪些场景下可以提⾼开发效率? 可否举个最明显的例⼦。 2. RAC 有哪些缺陷?⽐如RAC的哪些操作 执⾏效率⽐较低? 3.

    如何降低新同事的学习成本?即有⽊有 快速⼊⻔的系列教程可以推荐,适合⼊ ⻔的,中级的,深⼊的。 4. ReactiveCocoa 和 ReactiveSwift 啥关 系? ⼊⻔资料官⽅⽂档 基础⽤法都要熟悉 先回答第三题 中级 多实践,思维的转变,⽤函数式 去思考问题 深⼊ 看源码,了解底层实现,领悟 RAC的精髓。如何不⽤RAC实现 MVVM中的绑定操作?bind 和 Monad 范畴论
  9. 处理成功的回调 01 处理异常和错误 02 ⽀持取消操作 03 subscribenext 01 subscribeError 02

    disposable 03 异步处理 还能有效解决回调地狱的问题 PromiseKit (PromiseKit 是 RAC的 Continuation-Passing Style)
  10. 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
  11. 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.⽤⼀个消息中⼼或者消息总线来处理