一、2种编程方式
命令式编程:冯诺依曼 寄存机 计算器 (创建内存、计算内存、返回)
int factorial1(int x) {
int result = 1;
for (int i = 1; i <= x; ++i) {
result *= i;}
return result;
}
函数式编程:更推崇表达式 弱化语句 基于变量进行计算 不允许定义变量
int factorial2(int x) {
if (x == 1) return 1;
return x * factorial2(x - 1);
}
响应式编程:aotulayout(数学中的线相等式)
函数响应式编程:面向离散事件流,离散事件流操作(如excel的单元格)
二、流
FRP在Cocoa框架下的实现
提供基于时间变化的数据流的组合和变换
高阶函数:入参(是函数) 返回值(是函数)函数名
闭包:(函数跟变量等同) block是oc下闭包的实现
惰性计算: 在使用的时候才会计算
不改变状态: 不能够定义变量 (不用担心多线程改变这个变量,有多少核都能充分运用)
递归:调用函数
三、核心组件
- RACSteam:子类、RACSequence、RACSignal
- RACSequence:基于空间的数据流,更像数组和链表 ,Pull-driver:主动吸收 Data:id类型,里面可以是任意类型,sequence里可以嵌套sequence,时间上连续,消耗CPU较大时间缓慢
创建、变换、遍历
void sequence() {
RACSequence *sequence1 = [RACSequence return:@1];
RACSequence *sequence2 = [RACSequence sequenceWithHeadBlock:^id{
return @2;
} tailBlock:^RACSequence *{
return sequence1;
}];
RACSequence *sequence3 = @[@1, @2, @3].rac_sequence; 数组桥接
RACSequence *mappedSequence = [sequence1 map:^id(NSNumber *value) {
return @(value.integerValue * 3);
}];
RACSequence *concatedSequence = [sequence2 concat:mappedSequence];
RACSequence *mergedSequence = [RACSequence zip:@[concatedSequence,sequence3]];
NSLog(@"head is %@", mergedSequence.head);
for (id value in mergedSequence) {
NSLog(@"value is %@", value);
}
}
- RACSignal:基于时间的数据流,Push-driver:被动接受 Event:基于信号 有4种event 值、错误、终止、中断,把数据包含在value中,时间分散
创建、变换、遍历
void signalExample() {
RACSignal *signal1 = [RACSignal return:@"hello"];
RACSignal *signal2 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@1];
[subscriber sendNext:@2];
[subscriber sendCompleted];
return nil;
}];
RACSignal *signal3 = RACObserve(someObject, frame);
RACSignal *mappedSignal = [signal1 map:^id(NSString *value) {
return [value stringByAppendingString:@" world"];
}];
RACSignal *concatedSignal = [mappedSignal concat:signal2];
RACSignal *mergeSignal = [RACSignal merge:@[concatedSignal, signal3]];
[mergeSignal subscribeNext:^(id x) {
NSLog(@"next is %@", x);
} completed:^{
NSLog(@"completed");
}];
}
- RACSubscriber:Subscriber订阅Signal
- RACDisposable:Disposable是Signal的开关
- RACScheduler:用来做调度,代替GCD,异步与并发
- Cocoa框架适配工具
rac:适用于任何的异步场景 (解析json、3D模型绘制到屏幕上,压缩解压缩等同步场景不适用)
1.函数式编程不是面向对象编程的升级版,是一种变成范式
2.组成链式调用的必要条件就是在方法里面返回一个可被链式编程调用的对象,并不一定是对象自己
3.响应式编程可以用C语言这样的语言实现
4.ReactiveCocoa使用了KVO,但不是基于KVO的一个开源库,离开KVO也能运行
5.ReactiveCocoa不是一个纯函数式编程的库
6.下面的函数由于有赋值但仍是一个纯函数,没有进行二次赋值
没有改变参数也没有利用外界的变量
typedef int(^FunctionType1)(int x);
typedef int(^FunctionType2)(int x, int y);
FunctionType1 someFunction(FunctionType2 func, int x, FunctionType1 valueMap) {
int nextValue = valueMap(x);
return ^int(int y) {
return func(nextValue, y);
};
}
7. Pull-driver和Push-driver的区别?
pull-driver和push-dirver 的区别就是 “看书”和“看直播”的区别。 push-driver对未来的预期可以是清楚的,但是表示的是未来发生,而非随时发生。pull-driver的发生预期是清楚的。
8.怎么理解函数式语言中的引用透明?
根据参数产生结果,既不改变外部变量,也不基于外部变量,只是基于参数参数变化,引用透明就是指使用相同的参数对这样一个函数进行相同的调用,会得到相同的结果。基于引用透明,很多语言都能进行引用透明优化,不需要再次调用,只需存储结果
9.函数式语言主张不变量的原因是什么
任何数学模型中,不存在变量这一概念。变量不变,就没有一个很严格的执行顺序
10. 基于变量不可变(任何变量不允许二次赋值)来实现一个计算最大值的函数,定义如下
int max(int *array, int count)
(1)递归
int max(int *array, int count){
if (count < 1) return INT_MIN;
if (count == 1) return array[0];
int headMax = max(array, count - 1); //取得前count-1的最大值
return headMax > array[count - 1] ? headMax : array[count -1]; //最大值跟最后一个元素比较
}
(2) 高阶函数
typedef int (^ReduceType)(int acc,int next);
int fold(int *array, int count, ReduceType block, int first){
if (count == 0) return first;
return fold(array + 1, count - 1, block, block(first, array[0]));
}
void maxNumber(){
int array[] = {1,2,3,4,5,9,-1};
// NSArray *arr = @[@1,@2];
// [arr subarrayWithRange:NSMakeRange(1, arr.count -1)];
//求最大值
int max = fold(array, sizeof(array) / sizeof(int), ^int(int acc, int next) {
return acc > next ? acc : next;
}, INT_MIN);
//求最小值
int min = fold(array, sizeof(array) / sizeof(int), ^int(int acc, int next) {
return acc < next ? acc : next;
}, INT_MAX);
//求最乘积
int multiply = fold(array, sizeof(array) / sizeof(int), ^int(int acc, int next) {
return acc * next;
}, 1);
NSLog(@"max=%d",max);
}
11.自由发挥写一个高阶函数应用的例子,要求必须有返回函数的部分
# 例子中并没有包含返回函数的部分,可以用OC的block实现一个返回block的例子
typedef BOOL (^ConditionType)(int a);
//从一个数组中查找元素
int find(int *array, int count, ConditionType finder){
if (count == 0) return INT_MIN;
if (finder(array[0])) {
return array[0];
}
return find(array + 1, count - 1, finder);
}
//传入一个block用来判断,返回一个新的block,a传入之后判断取反进行返回
ConditionType not(ConditionType block)
{
return ^BOOL(int a){
return !block(a);
};
}
void test(){
int array[] = {1,2,3,4,5,9,-1};
ConditionType even = ^BOOL(int v) {
return v % 2 == 0;
};
int value = find(array, sizeof(array) / sizeof(int), even);
NSLog(@"偶数 ------(%d) -------",value); //value = 2;
int value2 = find(array, sizeof(array) / sizeof(int), not(even));
NSLog(@"奇数 ------(%d) -------",value2); //value2 = 1;
}