-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
executable file
·2272 lines (2238 loc) · 136 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>FRP</title>
<link rel="stylesheet" href="css/reveal.css">
<link rel="stylesheet" href="css/theme/custom.css">
<link rel="stylesheet" href="css/theme/league.css">
<!-- Theme used for syntax highlighting of code -->
<link rel="stylesheet" href="lib/css/zenburn.css">
<!-- Printing and PDF exports -->
<script>
var link = document.createElement('link');
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = window.location.search.match(/print-pdf/gi) ? 'css/print/pdf.css' : 'css/print/paper.css';
document.getElementsByTagName('head')[0].appendChild(link);
</script>
</head>
<body>
<div class="reveal">
<div class="slides">
<section data-transition="slide-in fade-out">
<h1>Functional Reactive Programming</h1>
<h4>a new way to deals with complexity</h4>
<p>
<small>
<a href="https://github.com/huanhulan">Lex Huang</a>, June 2018</small>
</p>
<aside class="notes">
今天主要和大家分享下函数式响应式编程。以sodium为例子。
有带电脑的同学可以打开http://10.32.60.158:8000/ 来在自己笔记本上观看ppt
</aside>
</section>
<section data-background="#000" data-transition="fade-in fade-out">
<h3 style="background: red">WARNING</h3>
<p>
<small>
Here is a simple introduction to
<i>Functional Reactive Programming</i> (FRP), we won't go deeper into the mathematical theories behind
the paradigm or explain the different implementations or types of it.
<br> Note that FRP fits some problems better than others. User interfaces and networking are two event-based
areas where it fits especially well. Not surprisingly, FRP is excellent for web applications. For
other situations, other paradigms like actor model would be more suitable.
</small>
<aside class="notes">
<p>不深入探讨数学原理</p>
<p>不探讨其他类型的frp及实现,只探讨push-based(数据驱动)的frp。还存在pull-based(需求驱动)的frp</p>
<p>问题域:如何编写更简洁更准确的事件驱动代码</p>
</aside>
</p>
</section>
<section data-transition="convex" data-background-transition="fade">
<section>
<h2>Let's start with a question</h2>
<div style="height:40vh;width:100%;">
<iframe src="" frameborder="0"></iframe>
<iframe src="" frameborder="0"></iframe>
</div>
<p>How to enhance progressively from left to right?</p>
<aside class="notes">
先给个问题,如何平滑地,简单的将左边的应用,过渡成右边的小游戏
</aside>
</section>
<section>
<h2>Project, meet complexity wall...</h2>
<p>Simple things taking too long.</p>
<p class="fragment">Rewritten from scratch!</p>
<p class="fragment">And a million dollars later...</p>
<p class="fragment">It hits the same wall again!</p>
<aside class="notes">
<p>sodium的作者参与了一个基于JAVA的嵌入式系统的配置工具的开发,当项目进展问题域:基于事件到某一阶段的时候,软件甚至难以在2周内增加一个check box到屏幕上 因为他们不得不将布尔值传递到嵌套很深的接口和抽象层里去。
</p>
<p>为了解决这个问题,他们设计出了一个响应式编程库,后来发现他们构建了一个最基础FRP系统。而使用这个库后,再实现同样的需求,只需要一行代码。</p>
<p>这里我们通过一个简单的方法来度量复杂度:为了理解一个程序所要花费的人力和时间。</p>
</aside>
</section>
<section>
<img src="img/disaster.jpg" alt="">
</section>
</section>
<section>
<section>
<h2>What goes wrong?</h2>
<img src="img/questioning1.jpg" alt="">
</section>
<section>
<h3>The State machines are great</h3>
<div class="book-introduction">
<img class="book-introduction__book" src="./img/state-machine.png" alt="book">
<div class="book-introduction__info">
<p>The old school
<i>state machine</i> works in the following way:</p>
<ol>
<li>An input event comes into the system.</li>
<li>The program logic makes decisions based on the input event and the current program state.
</li>
<li>The program logic changes the program state.</li>
<li>The program logic may also produce output.</li>
</ol>
<p>
We could say that all programs are fundamentally state machines.
</p>
</div>
</div>
<aside class="notes">
状态机是一个很棒的理念,根据输入和现有的状态决定程序的下一走向。某种意义上所有程序都是状态机。
</aside>
</section>
<section>
<h3>but...</h3>
<p>codes written in a traditional state-machine style tends to be
<b>unreadable</b> and
<b>brittle</b>. </p>
<p>codes become
<b>hard to reason about</b> as the program goes bigger.</p>
<p>And a programmer’s main task is to structure clean codes.</p>
<aside class="notes">
但是问题在于代码编写层面。
状态机很容易让代码变得难懂和零碎。这样随着程序规模的扩大而变得难以维护。
</aside>
</section>
<section>
<h3>
<b>Observer-pattern</b> saves the day! </h3>
<h4>But wait...</h4>
<img src="img/six-plagues.png" alt="six plagues of Observer-pattern" width="60%" style="margin: 0;">
<footer>
<small>six plagues of Observer-pattern</small>
</footer>
<aside class="notes">
<ul>
<li>
<b>不可预测顺序</b>—在一个复杂的侦听器构成的网络中,事件的接收顺序依赖于监听器的注册顺序。这种隐性依赖是有害的。 FRP 使事件的处理顺序无关紧要, 因为从外部是无法察觉到离散的事件的。
<p>比如,B&C同时监听A,而C还监听了B,则对于C,我们很难判断是B的事件先还是A的事件先到达</p>
</li>
<li>
<b>错过第一个事件</b>—这可能很难保证你在发送第一个事件的时候已经注册你的监听器。FRP 是事务性的, 所以有可能提供此项保证。
</li>
<li>
<b>混乱状态</b>—回调将代码变成了传统的状态机风格,这很容易让代码变得难以维护。而FRP带来了秩序。
</li>
<li>
<b>线程问题</b>—试图使侦听器线程安全可能导致死锁, 而且很难保证在注销侦听程序后不会收到更多回调。FRP消除了这些问题。
</li>
<li>
<b>泄露回调</b> —如果忘记取消注册侦听器, 程序将会有内存泄漏。侦听器会反转自然数据依赖性, 但不像我们希望的那样反转存活时间上的依赖关系。FRP可以做到这一点。
</li>
<li>
<b>不小心地递归</b>—更新本地状态和通知侦听器的顺序可能是致命的, 容易犯错误,比如在一个监听器里发送事件可能导致程序进入递归。FRP消除了这个问题。
</li>
</ul>
以上问题就容易造成当状态机和观察者模式结合的时候,容易出现状态混乱。
</aside>
</section>
<section data-background-image="">
<h3>When State gets messy...</h3>
<div class="book-introduction">
<img class="book-introduction__book" src="img/reboot.jpg" alt="book">
<div class="book-introduction__info">
<p>
<b>KEEP CALM</b> and
<b>REBOOT</b>.</p>
<p class="fragment">
<b>CTRL+ALT+DELETE</b> fixes everything.</p>
<p class="fragment">If all else fails,
<b>RESTART</b>.</p>
<p class="fragment">Still not work?</p>
<p class="fragment">
<b>Restart the world!</b>
</p>
</div>
</div>
<aside class="notes">
状态混乱的时候怎么办呢?<br>
保持冷静 <br>
重启程序 <br>
CTRL+ALT+DELET <br>
重启电脑 <br>
重启世界
</aside>
</section>
<section data-background-image="img/Nukesds2.webp"></section>
</section>
<section data-transition="convex">
<section>
<h3>Here comes the
<b>functional reactive programming</b>
<i>(frp)</i>
</h3>
<p>A specific method of
<b>reactive programming</b> that enforces the rules of functional programming, particularly the property
of
<b>compositionality</b>.</p>
<p>
<small>
<a href="http://conal.net/">Conal Elliott</a> is one of the inventors of FRP, this concept was first introduced in his paper
<i>
<a href="http://conal.net/papers/icfp97/">Functional Reactive Animation
</a>
</i> to composing richly interactive, multi-media animations.
</small>
</p>
<aside class="notes">
函数式响应编程可以给刚刚提到的6个bug提供一个解决途径。<br>
这是用函数式编程的“组合性”思想应用于响应式编程上的一个结合产物。<br>
Conal Elliott 是这种编程范式的发明者之一。这个概念第一次出现在他的论文Functional Reactive Animation 中
</aside>
</section>
<section>
<h2>Core Pieces:</h2>
<p class="fragment"><b>Cells</b>: Continuous values over time</p>
<p class="fragment"><b>Streams</b>: Discrete events pushed into the FRP sys.</p>
<br />
<p class="fragment"><i>Declarative</i> combinators that guarantee sensible composition.</p>
</section>
<section>
<h2>Cell</h2>
<pre><code class="typescript" data-trim>
const num = new Cell<number>(1);
const doubled = num.map(n => n * 2);
// <Cell<A>>.lift( b: Cell<B>, (A, B) => C): Cell<C>
const added = num.lift( doubled, (n, d) => n + d);
</code></pre>
<p>Always has a value</p>
</section>
<section>
<h2>Streams</h2>
<pre><code class="hljs typescript" data-trim>
const nums = new StreamSink<number>();
const doubled: Stream<number> = num.map(n => n * 2);
const evens: Stream<number> = num.filter(n => n % 2 === 0);
nums.send(2);
</code></pre>
<p>Fires at discrete points in time with a value.</p>
<aside class="notes">
之后我会具体介绍这两个类型及其运算符。
</aside>
</section>
<section>
<h3>I've heard 2 names of different programming paradigms!</h3>
<img src="img/lay-of-land.png" alt="">
<p>FRP is a subset of both functional and reactive programming.</p>
</section>
<section>
<h3>What is reactive programming</h3>
<div class="book-introduction">
<img src="img/rxjs.png" alt="rxjs" class="book-introduction__book">
<div class="book-introduction__info">
<p>A broad term meaning that a program is </p>
<ol>
<li>
<b>event-based</b>,</li>
<li>acts in response to input, and</li>
<li>is viewed as a
<b>flow of data</b>, instead of the traditional flow of control.</li>
</ol>
<p> It doesn’t dictate any specific method of achieving these aims. Reactive programming gives
<b>looser coupling</b> between program components, so the code is more modular.
</p>
<p> Microsoft’s
<i>
<a href="http://reactivex.io/">Reactive Extensions</a>
</i> (
<b>Rx</b>) is mostly concerned with chaining event handlers, and it gives you many options for
how you do it. </p>
</div>
</div>
<aside class="notes">
响应式编程是一个比较宽泛的概念。大体上来说,这种编程范式有如下特点:<br>
1. 基于事件<br>
2. 对输入做出响应<br>
3. 可以将事件看作是数据流,而不是控制流<br>
这种编程范式强调松耦合,因而天生适合模块化编程。<br>
微软的Rx是它的一种实现。链式操作是其最大一个特征。
</aside>
</section>
<section data-background-image="img/lambda.png">
<h3>What is functional-programming</h3>
<p>
<small>A style or paradigm of programming based on functions, in the mathematical sense of the word. It
deliberately avoids shared mutable state, so it implies the use of immutable data structures,
and it emphasizes
<b>
<i>Compositionality</i>
</b> and
<b>Referential transparency</b>
</small>
</p>
<aside class="notes">函数式编程基于数学定义中的函数,强调不变性,特点是复合性原理和引用透明性</aside>
</section>
<section>
<h3>what's the
<i>compositionality</i>
</h3>
<p>The
<b>principle of compositionality</b>:</p>
<blockquote>
The meaning of an expression is determined by the <u>meanings</u> of its parts and the rules used to combine them.
</blockquote>
<div data-markdown>
<script type="text/template">
Thus the javascript code
```javascript
const foo = x=>f(g(x))
```
is equal to haskell code
```haskell
foo=f . g
```
since they all mean *g composed with f*.
</script>
</div>
<aside class="notes">
<p>在数学、语义学和语言哲学中,复合性原理是指,一个复杂表达式E的意义是由E的其各组成部分的意义以及E的语义结构(也就是用以结合其个组成部分的规则)来决定的。</p>
<p>
复合性原理认为,在有意义的句子中,如果实词部分被从句子中脱离出去,所剩下的东西就是复合的规则。例如句子“苏格拉底是哲学家”。一旦有意义的词法项“苏格拉底”和“哲学家”被取走,剩下了“是”就用來为描述“苏格拉底”和“哲学家”之关系。
</p>
<p>这就要求我们理解“意义”的定义(这是我将meaning标注出来的原因),在语义学上,“意义”表示的是通过人类语言表达的信息内容,信息有结构,结构则隐含了复杂度,而作为程序员,我们和复杂度做斗争。</p>
</aside>
</section>
<section>
<h3>how does compositionality help</h3>
<p>
<small>
Without compositionality, the consequences of composing program modules are ad hoc.
</small>
</p>
<hr>
<p>
<small>FRP is compositional because it imposes mathematical rules that force the interaction of program
elements to be simple and predictable by using
<i>denotational semantics
</i>. So we can think in teams of dependency and think declaratively.
</small>
</p>
<aside class="notes">
<p>在没有复合性原理的情况下,程序模块之间的运行的结果是不稳定的。而有了复合性原理则可以使的程序的含义独立于顺序,只要其组成部分和组合规则表达同样的含义就行。这样我们就可以从依赖和声明的角度思考程序</p>
</aside>
</section>
<section>
<h3>what is Referential transparency</h3>
<blockquote class="quote">
<p>
<small>
Referential transparency is an oft-touted property of (pure) functional languages, which makes it easier to reason about
the behavior of programs. I don't think there is any formal definition, but it usually means
that an expression always evaluates to the same result in any context. Side effects like
(uncontrolled) imperative update break this desirable property. C and ML are languages with
constructs that are not referentially transparent.
</small>
</p>
<footer>
<small>from
<a href="https://wiki.haskell.org/Referential_transparency">Haskell wiki</a>
</small>
</footer>
</blockquote>
<aside class="notes">
引用透明性可以被理解为一个表达式的结果独立于其所处的上下文,函数的返回值只依赖于其输入值,输入值不变,输出则不变。
</aside>
</section>
<section>
<h3>Too Metaphysica? </h3>
<img src="img/questioning2.jpg.jpg" alt="">
<aside class="notes">这样说可能太过形而上了点。那么我这里直接给出一些实际的指导原则。</aside>
</section>
<section>
<h4>So let's be practical</h4>
<ul>
<li>
<small>You must not perform any I/O.</small>
</li>
<li>
<small>You must not throw any exceptions unless they’re caught and handled within the function.
</small>
</li>
<li>
<small>You must not read the value of any external variable if its value can change, but constants are
allowed and encouraged.
</small>
</li>
<li>
<small>You must not modify any externally visible state.</small>
</li>
<li>
<small>You must not keep any state between invocations of the function.</small>
</li>
</ul>
<p class="fragment">In short, the function must have
<b>no external effects</b> other than through the returned value, and it must
<b>not be affected by any external state</b>.</p>
<aside class="notes">
<ul>
<li>不做i/o</li>
<li>在函数内部处理异常</li>
<li>函数不读取于外部变量</li>
<li>函数不修改外部变量</li>
<li>在函数调用之间不保存任何状态</li>
</ul>
长话短说就是函数除了返回值外对外没有别的作用,也不会引起外部状态的改变。
</aside>
</section>
<section>
<h4>the beauty of purity</h4>
<img src="img/pure.png" alt="">
</section>
<section>
<h3>Thinking in terms of
<b>dependency</b>
<br>
<small>vs</small>
<br> Thinking in terms of
<b>sequence</b>
</h3>
<div class="book-introduction">
<img src="img/non-FRP%20style.jpg" alt="" class="book-introduction__book">
<div class="book-introduction__info">
<p>
Traditionally, software is expressed as a sequence of steps.
</p>
<p>
The problem with representing dependencies as a sequence comes when you go to change the code.
</p>
</div>
</div>
<aside class="notes">
一般来说,软件是由步骤序列来表示的。每一步都和前几步相关。
这种将依赖用时序来表达的问题在于会给修改代码造成困难。
</aside>
</section>
<section>
<h3 style="display: none">Thinking in terms of
<b>dependency</b>
<br>
<small>vs</small>
<br> Thinking in terms of
<b>sequence</b>
</h3>
<div class="book-introduction">
<div class="book-introduction__book">
<a href="#/6/5"><img src="img/minimal.png" alt="conceptual diagram"></a>
<footer>
<small>Given a conceptual diagram like the above, we can extract the dependency relationships easily
</small>
</footer>
</div>
<div class="book-introduction__info">
<p>In FRP, you express dependencies directly, but express it using a <b>directed graph</b>.</p>
<p>So you can just add or remove the dependencies, and the sequence is automatically updated. It’s
impossible to make a sequence mistake.</p>
</div>
</div>
<aside class="notes">
在frp中,我们通过数据流向图的形式来声明依赖。而程序执行时序上的关系由frp引擎来决定。
这样做的好处在于可以简单地通过修改流和节点而自动地修改依赖关系,避免由于错误的代码调用顺序造成的错误。
</aside>
</section>
<section>
<h3>Thinking declaratively</h3>
<h4>what the program is, not what it does</h4>
<aside class="notes">
在介绍函数式编程的时候,我还提到了以声明的方式思考。那我们接下来看看,它到底是什么样一种思考方式。
粗略来看,就是思考东西的含义是什么,而不是它做了什么。
</aside>
</section>
<section>
<h3 style="display: none">Thinking declarative</h3>
<p>How to cook a lasagna?</p>
<ol>
<li class="fragment">
<small>Heat oven to 350°F.</small>
</li>
<li class="fragment">
<small>Brown meat in large skillet on medium-high heat. Meanwhile, mix 1-1/4 cups mozzarella, ricotta,
1/4 cup Parmesan, parsley and egg until blended.Drain meat;
</small>
</li>
<li class="fragment">
<small>return to skillet. Stir in pasta sauce. Pour water into empty sauce jar; cover and
shake well. Add to skillet; stir until blended.
</small>
</li>
<li class="fragment">
...
</li>
</ol>
<aside class="notes">
<p>这里不要说出lasagana[ləˈsɑnjə]的中文名:意大利千层面</p>
<ul>
<li>炒锅烧热入少许橄榄油,爆香洋葱碎;然后放入白蘑菇翻炒。</li>
<li>翻炒均匀后,放入红椒丁继续翻炒。</li>
<li>加入牛肉馅,大火翻炒至变色。</li>
<li>倒入番茄膏,入胡椒粉、盐调味,搅拌均匀。 </li>
<li>不用加盖,用小火慢慢炖,让蔬菜的水份适当蒸发,大约15-20分钟,即成肉酱。</li>
<li>准备一方型烤盘,盘底抹油防粘,然后铺上肉酱,为第一层。</li>
<li>铺上干面皮,为第二层。</li>
<li>干面皮上涂抹上白色精华酱,为第三层。</li>
<li>如此反复,再铺上肉酱——干面皮——白色精华酱,按此程序反复操作3遍。(共三层干面皮,操作完毕后,最上层应是白色精华酱)</li>
<li>表面均匀撒上马苏里拉奶酪丝。</li>
<li>放入预热好的烤箱200度,中层上下火约60分钟至表皮金黄即成。 </li>
</ul>
<p>说了这么多,大家能想想这道菜长什么样么</p>
</aside>
</section>
<section>
<h3 style="display: none">Thinking declarative</h3>
<p>Nope! This is no way to write a cookbook:
<br> it’s an
<b>operational definition</b> of lasagna</p>
<aside class="notes">很难,这其实是一个操作说明,很难直观想象菜品的样子。</aside>
</section>
<section>
<h3 style="display: none">Thinking declarative</h3>
<p>This is how our cookbook would be written:</p>
<ol>
<li>
<small>
<i>Lasagna</i>
<b>is</b> grated cheese
<b>on</b> cheese sauce
<b>on</b> flat pasta
<b>on</b>
cheese sauce
<b>on</b>
Bolognese
<b>on</b> flat pasta
<b>on</b> cheese sauce
<b>on</b> Bolognese
<b>on</b> flat pasta
<b>on</b> cheese sauce baked for 45 minutes.
</small>
</li>
<li>
<small>
<i>Bolognese</i>
<b>is</b> onion and oil fried until golden mixed with ground beef mixed with tomato simmered
for 20 minutes.
</small>
</li>
<li>
<small>
<i>Cheese sauce</i>
<b>is</b> milk and cheese added progressively to
<i>roux</i> while frying it until the sauce thickens.
</small>
</li>
<li>
<small>
<i>Roux</i>
<b>is</b> flour and butter fried briefly</small>
</li>
<li>
<small>
<i>Baked</i>
<b>is</b> put in an oven dish in a hot oven.</small>
</li>
<li>
<small>
<i>Fried</i>
<b>is</b> put in a pan on high and mixed frequently</small>
</li>
<li>
<small>
<i>Simmered</i>
<b>is</b> put in a pan on low and mixed infrequently</small>
</li>
</ol>
<aside class="notes">
<p>lasagna是磨碎的干酪沙司放在芝士酱上放在宽意大利面条上放在奶酪酱上放在肉酱上放在宽意大利面条上放在芝士酱上放在肉酱上放在宽意大利面条上放在芝士酱上,烤45分钟。</p>
<p>肉酱是洋葱和油煎至金黄色,混合了碎牛肉和番茄炖20分钟。</p>
<p>芝士酱是牛奶和奶酪,在炒菜的过程中逐渐加入乳酪面,直到酱汁变稠。</p>
<p>乳酪面是面粉和黄油,简单煎一下。</p>
<p>烤指的是将烤盘放入热烤炉。</p>
<p>油炸是在高火锅中快速搅拌。</p>
<p>炖指的是文火锅里,不经常搅拌。</p>
<p>flat pasta:宽意大利面条</p>
<p>Bolognese:肉酱</p>
<p>Roux:奶油炒面糊</p>
<p>Baked:烤</p>
<p>Fried:煎</p>
<p>Simmered:炖</p>
</aside>
</section>
<section data-background-image="img/lasagna.jpg">
<h3 style="display: none">Thinking declaratively</h3>
</section>
<section>
<h3 style="display: none">Thinking declaratively</h3>
<p>Notice a few things:</p>
<ul>
<li class="fragment">
We express dependencies directly. The sequence is derived from them.
</li>
<li class="fragment">
It’s closer to a conceptual view of the food, so it’s easy to understand.
</li>
<li class="fragment">
We can compose the parts into new recipes easily.
</li>
</ul>
<aside class="notes">
<p>我们直接表达了依赖,而顺序则从依赖中得到表达。也就是说我们不在乎起司酱是在肉酱前做的还是后做的。我们只关心它放在谁上面。</p>
<p>这样更接近概念上的食物,更容易理解</p>
<p>我们很容易将它混入到别的菜品制作过程中以得到新的食谱</p>
</aside>
</section>
<section>
<h3>Thinking declaratively</h3>
<div data-markdown>
<script type="text/template">
```Haskell
Map f xs = [f x | x<-xs];
```
</script>
</div>
<p>vs</p>
<div data-markdown>
<script type="text/template">
```Haskell
Map f [] = [];
Map f [x:xs] = f x : map f xs;
```
</script>
</div>
<footer>
<small>
Common declarative languages include those of
<a href="https://en.wikipedia.org/wiki/Database_query_language" class="mw-redirect" title="Database query language">database query languages</a> (e.g.,
<a href="https://en.wikipedia.org/wiki/SQL" title="SQL">SQL</a>,
<a href="https://en.wikipedia.org/wiki/XQuery" title="XQuery">XQuery</a>),
<a href="https://en.wikipedia.org/wiki/Regular_expression" title="Regular expression">regular expressions
</a>,
<a href="https://en.wikipedia.org/wiki/Logic_programming" title="Logic programming">logic programming
</a>,
<a href="https://en.wikipedia.org/wiki/Functional_programming" title="Functional programming">functional programming
</a>, and
<a href="https://en.wikipedia.org/wiki/Configuration_management" title="Configuration management">configuration management
</a> systems.
</small>
</footer>
</section>
<section>
<h2>Wait...Why not just fix listeners?</h2>
<p>If you fix the problems with listeners, you’ll invent FRP. </p>
<aside class="notes">
<p>实现一个FRP系统还是比较难的。Sodium团队在参考别人的实现的同时依旧花了6人月的工作量来理解和开发Sodium。而最初版本的库只有1000行代码!</p>
<p>Sodium团队认为困难在于事件处理机制本身是困难的,在没有frp库的帮助下,我们每天都在和观察者模式带来的小麻烦作斗争,而写一个frp库则需要一次性对付所有问题。</p>
</aside>
</section>
</section>
<section data-transition="convex">
<section>
<h2>Introducing
<b>Sodium</b>
</h2>
<div class="book-introduction">
<div class="book-introduction__book">
<a href="https://www.manning.com/books/functional-reactive-programming">
<img src="./img/Blackheath-FRP-HI.jpg" alt="book">
</a>
</div>
<div class="book-introduction__info">
<blockquote class="book-quote">
<p>A gentle introduction to the necessary concepts of FRP.</p>
<footer>From the Foreword by Heinrich Apfelmus, author of the Reactive-banana FRP library
</footer>
</blockquote>
<div data-markdown>
<script type="text/template">
* [Book](https://www.manning.com/books/functional-reactive-programming)
* [GitHub](https://github.com/SodiumFRP)
* [Forum](http://sodium.nz/)
</script>
</div>
</div>
</div>
<aside class="notes">
以下以sodium项目中的sodiumjs为例子来介绍frp。这个项目主要为非函数式编程语言提供了正确的frp实现。包括java、c#、c++、swift、rust、Typescript等实现。对于函数式编程语言,frp库的选择有很多,比如sodium之前就有haskell实现,之后由于reactive
banana这个库的流行,因此sodium项目组不再维护haskell版的sodium。 之所以是用typescript实现,是因为函数式编程本身就是追求强类型的。
</aside>
</section>
<section>
<h3>Life cycle of FRP</h3>
<div class="book-introduction">
<div class="book-introduction__book">
<img src="img/life-cycle-FRP.png" alt="">
</div>
<ul class="book-introduction__info">
<li>
<h4>Stage 1: Initialization</h4>
<p>Typically during program startup, FRP code statements are converted into a directed graph
in memory.</p>
</li>
<li>
<h4>Stage 2: Running</h4>
<p>For the rest of the program execution you feed in values and turn the crank handle, and the
FRP engine produces output.</p>
</li>
</ul>
</div>
<aside class="notes">
<p>1.初始化:根据声明在内存中构造有向图。</p>
<p>2.运行:在其他程序执行的时候FRP引擎则根据用户输入产生输出</p>
<p>
sodium的FRP逻辑是数据驱动的(push-based)。数据通过两个数据结构Stream和Cell流入逻辑图中。FRP代码对输入作出响应。数据从输入流向输出。
</p>
</aside>
</section>
<section>
<h2>Operators of the two core data types</h2>
<table class="table">
<thead>
<tr>
<th>
<b>Data Type</b>
</th>
<th>Outputs a Stream</th>
<th>Outputs a Cell</th>
<th>Outputs a value</th>
</tr>
</thead>
<tbody>
<tr>
<th><a href="/#/5/2">Stream</a></th>
<td>
<ul>
<li>
<a href="/#/5/5">never()</a>
</li>
<li>
<a href="/#/5/6">map()</a>
</li>
<li>
<a href="/#/5/7">merge()</a> /
<a href="/#/5/12">orElse()</a>
</li>
<li>
<a href="/#/5/13">snapshot()</a>
</li>
<li>
<a href="/#/5/15">filter()</a>
</li>
</ul>
</td>
<td>
<ul>
<li>
<a href="/#/5/17">hold()</a>
</li>
</ul>
</td>
<td></td>
</tr>
<tr>
<th><a href="/#/5/3">Cell</a></th>
<td>
<ul>
<li>
<a href="/#/5/29">switchS()</a>
</li>
</ul>
</td>
<td>
<ul>
<li>
<a href="/#/5/24">map()</a>
</li>
<li>
<a href="/#/5/22">lift()</a>
</li>
<li>
<a href="/#/5/28">switchC()</a>
</li>
</ul>
</td>
<td>
<ul>
<li>
<a href="/#/5/25">sample()</a>
</li>
</ul>
</td>
</tr>
</tbody>
</table>
<aside class="notes">
这一节主要以sodium为例子介绍frp库的数据结构和基本操作符。这些操作符主要是来构造frp逻辑(frp向量图)的。 这节之后会介绍如何让frp逻辑与外界程序进行交互。
</aside>
</section>
<section>
<h3 style="position: relative;">
<a href="/#/5/1" style="position: absolute;left:0;top:0;bottom:0;margin:auto;text-transform:lowercase;font-size:50%;">←</a> Stream</h3>
<p>class Stream<A></p>
<ul>
<li>
<p>Stream represents a stream of events.</p>
<ul>
<li>Manipulate the whole stream, not individual occurrences.</li>
</ul>
</li>
<li>Has a type parameter, e.g.
<br>
<b>new Stream<MouseEvent>()</b>
</li>
</ul>
<aside class="notes">
<ul>
<li>事件—一条异步信息从程序的一部分传递到另一部分的过程</li>
<li>Stream—一连串离散事件。当事件通过流传播时,我们有时会说流被触发了. 在其他 FRP 系统中也成为事件流、 observable, or a signal。
</li>
</ul>
</aside>
</section>
<section>
<h3 style="position: relative;">
<a href="/#/5/1" style="position: absolute;left:0;top:0;bottom:0;margin:auto;text-transform:lowercase;font-size:50%;">←</a> Cell</h3>
<h4>a value that changes over time</h4>
<p>class Cell<A></p>
<p>Cell is a <b>mutable</b> variable——because it represents the state mutation</p>
<p><a href="/#/5/4">What about referential transparency?</a></p>
<aside class="notes">
cell用来存放/代表应用的状态。举几个例子:
<ul>
<li>鼠标在应用窗口中的坐标</li>
<li>游戏中的人物坐标</li>
<li>时间</li>
<li>汽车的速度, 汽车的里程表, 当前的GPS定位</li>
</ul>
</aside>
</section>
<section>
<h3 style="position: relative;"><a href="/#/5/3" style="position: absolute;left:0;top:0;bottom:0;margin:auto;text-transform:lowercase;font-size:50%;">←</a>In horror stories, demons can never be killed; </h3>
<h4>they can only be banished.</h4>
<img src="./img/seal.jpg" alt="">
<p>In a similar way, FRP takes the evil of event handling, divides it into little pieces, and
then banishes each piece into an evil-proof box called a stream or a cell. </p>
<aside class="notes">
恐怖电影里,恶魔往往不会被杀死,而是被封印。这样做的好处是,你总可以拍续集来骗钱。
frp也类似,通过将“邪恶”的事件处理分割放在stream和cell这样可以遵循函数式编程原则的数据结构里,来规避麻烦。
虽然Cell里的值是mutable,是可以有副作用的,但是Cell和Stream本身却是immutable的
对了解函数式编程的同学,可以把Cell看做是一个 <a href="https://www.youtube.com/watch?v=b0EF0VTs9Dc">monad</a>,事实上,Stream也是一个monad。至于原因,待会儿降到它的lift操作符时,我会介绍。
</aside>
</section>
<section>
<h3 style="position: relative;">
<a href="/#/5/1" style="position: absolute;left:0;top:0;bottom:0;margin:auto;text-transform:lowercase;font-size:50%;">←</a> The
<b>never</b> primitive</h3>
<h4>a stream that never fires</h4>
<p>never :: Stream a</p>
<p>In Sodium it doesn’t have the name
<i>never</i>. If A stream constructed in the way has no mechanism to cause it to fire, so it’s guaranteed
never to fire.</p>
<aside class="notes">
<p>never 主要用来移除你不需要的逻辑。两种构造方式:
<ul>
<li>构造一个没有触发器的流来得到</li>
<li>将一个流通过filter等操作转换成never</li>
</ul>
</p>
</aside>
</section>
<section>
<h3 style="position: relative;">
<a href="/#/5/1" style="position: absolute;left:0;top:0;bottom:0;margin:auto;text-transform:lowercase;font-size:50%;">←</a> The
<b>map</b> primitive</h3>
<h4>transforming a value</h4>
<p>map :: (a -> b) -> Stream a -> Stream b</p>
<div data-markdown>
<script type="text/template">
```typescript
const clickStream = new Stream<MouseEvent>();
// emit `true` whenever the `clickStream` fires.
const clickSignal = clickStream.map(e=>true);
```
</script>
</div>
<img src="./img/functor.png" alt="functor">
<aside class="notes">
通过一个转换函数,将带有A类型的stream转换成b类型stream
<p>map在函数是编程里可以认为是一个functor(函子)</p>
<p>直观理解是,它将两个stream里的值取出来,通过一个接收一个有函数,用旧stream调用这个函子,得到新的Stream</p>
</aside>
</section>
<section>
<h3 style="position: relative;">
<a href="/#/5/1" style="position: absolute;left:0;top:0;bottom:0;margin:auto;text-transform:lowercase;font-size:50%;">←</a> The
<b>merge</b> primitive</h3>
<h4>merging streams</h4>
<p>merge :: Stream a -> Stream a -> Stream a</p>
<div data-markdown>
<script type="text/template">
```typescript
const clickStream = new Stream<MouseEvent>();
const keyboardStream = new Stream<KeyboardEvent>();
/*
* gets `true` whenever tapping the keyboard
* or click the mouse
*/
const inputStream = clickStream.merge( keyboardStream,
(m,k)=>true );
```
</script>
</div>
<a href="/#/5/8" class="link">why do we need it?</a>
<aside class="notes">
合并两个stream,为什么我们需要合并stream呢?特别是对于js这种单线程语言来说
</aside>
</section>
<section>
<h3 style="position: relative;">
<a href="/#/5/7" style="position: absolute;left:0;top:0;bottom:0;margin:auto;text-transform:lowercase;font-size:50%;">←</a> Simultaneous events</h3>
<p>
Two or more stream events that occur in the same
<a href="/#/5/9">transaction</a>
</p>
<aside class="notes">两个及以上的事件在同一个事物中发生了。</aside>
</section>
<section>
<h3 style="position: relative;">
<a href="/#/5/7" style="position: absolute;left:0;top:0;bottom:0;margin:auto;text-transform:lowercase;font-size:50%;">←</a> Transaction</h3>
<ul>
<li>This is basically the same idea as the transactions used in databases.</li>
<li>FRP processing takes place in a transactional context.</li>
<li>Sodium automatically starts a transaction whenever an input value is pushed into a stream or cell.
</li>
<li>Any state changes that occur as a result of that input are performed within the same transaction.</li>
</ul>
<a href="/#/5/10">let's see an example</a>
<aside class="notes">
这等同于数据库事务 <br>
frp处理开始于一个事务上下文中 <br>
sodium会在输入被送入一个stream或者cell的时候自动开启新的事务 <br>
所有由于输入所带来的状态变动都会在同一个事物中被处理 <br>
虽然v8是单线程的,一次只能处理一个异步事件,但是在sodium内,一个frp外部输入可以同时触发多个stream。这是“并行”的本质。 光看文字比较抽象。那回到merge,看看他们之间有什么关系?
</aside>
</section>
<section>
<h4 style="position: relative;">
<a href="/#/5/7" style="position: absolute;left:0;top:0;bottom:0;margin:auto;text-transform:lowercase;font-size:50%;">←</a> EXAMPLE: SIMULTANEOUS EVENTS IN A DRAWING PROGRAM</h4>
<div class="book-introduction">
<img class="book-introduction__book" src="./img/dragNdrop.png" alt="book">
<div class="book-introduction__info">
<ul>
<li>If you click an item, the mouse becomes selected.</li>
<li>If an item is selected, and you click elsewhere, the item gets deselected.</li>
</ul>
<p>But No.3 on the left, a single mouse click will cause two simultaneous events to be generated:
<ul>
<li>Deselecting the triangle</li>
<li>Selecting the octagon</li>
</ul>
</p>
<p>You’ll almost certainly want to merge these streams
at some point in the program. Because these two
events originate in the same mouse click event,
they’re simultaneous. </p>
<p>Otherwise, you will get a glitch of the cursor style.</p>
</div>
</div>
<aside class="notes">
<ul>
<li>如果点击一个物品,则鼠标状态展示为选中状态</li>
<li>如果以物品为选中状态,点击别的地方会变为不选中</li>
</ul>
<p>但是左边 No.3 场景, 一个鼠标点击会造成两个事件的产生:
<ul>
<li>不选中三角形</li>
<li>选中八边形</li>
</ul>
</p>
<p>这个时候我们自然希望鼠标样式保持选中状态不变,而不会有一次抖动</p>
</aside>
</section>
<section>
<img src="./img/merge.png" alt="merge">
<p>The mechanics of how merge deals with
simultaneous events</p>
<aside class="notes">
<p>
如图所示,在一个transaction内,同时处理了这两个事件,而在结束时候,两个事件的正确结果被输出了。这样我们就避免了鼠标的样式抖动。
</p>
现在我们停下来想下,在react-redux的机制内,我们如果要处理相同的问题可能会非常复杂,因为两个不同的action会产生不同的state,
而如果想让两个action相互协作,则需要额外的精力,带来额外的复杂度。比如引入react-saga这样的东西。而这种状态维护中间件有会进一步影响性能和程序复杂度。
前几天,有个哥们用react+redux-saga撸了一个<a href="http://shinima.pw/battle-city/#/gameover">坦克大战</a>,就遇到了性能和复杂度的问题。当然他也很聪明的另辟蹊径解决了。
</aside>
</section>