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

Functional Ruby

E181d174303811fefaefb0b3a91ce567?s=47 Jichao Ouyang
September 24, 2016

Functional Ruby

- first class function
- pattern matching
- category theory
- pure program in Functional way

E181d174303811fefaefb0b3a91ce567?s=128

Jichao Ouyang

September 24, 2016
Tweet

Transcript

  1. 函数式 Ruby 编程 欧阳继超

  2. Agenda 什么是函数式编程 Ruby 的一些函数式特性 使用 Monad 纯化/ 简化控制流

  3. FBI Warning 用 Nokia 的同学请自己手动输入 git.io/fprb

  4. 我是...

  5. 我是...

  6. None
  7. None
  8. 我还是

  9. 啊? 所以是... 一个会点 Scala 的 JavaScript 程序员来教 Rubyist 函数式编程?

  10. 我在 JavaScript 社区讲函数式的时候, 观众是这样 的...

  11. Ruby 函数式 ? https://cloud.githubusercontent.com/assets/1235045/17933311/321ff7d2-6a46-11e6-903e- 8cc84f3acc78.JPG You might be surprised to

    see Ruby in the list of functional languages because they generally count as object oriented languages. -- Martin Odersky 你可能奇怪我把Ruby 也放到了函数式语言的列表, 这些语言通常会被归到面向对 象语言. -- Scala 之父
  12. 什么是函数式 一等函数 first class function / 入 lambda 纯 purity

    引用透明性 referential transparency 无副作用 side effectless 不可变 immutability 持久化数据结构 persistent data structures ... 当纯到一定程度可能就需要 范畴论 Catergory Theory
  13. None
  14. 好处呢? 好组合 composible 好推理 easy to reason about 好测试 easy

    to test 好多线程 Multi-thread 好玩 fun 好 高逼格 high bigger elegant
  15. 你可能不知道的Ruby

  16. lambda aka 匿名函数 [ 多选题] 请选出所有的 lambda A : {

    } / d o e n d # s u c h a s = [ 1 , 2 , 3 ] . m a p { | x | x + 1 } = B : p l u s 1 = l a m b d a { | x | x + 1 } C : p l u s 1 = - > ( x ) { x + 1 } D : p l u s 1 = P r o c . n e w { | x | x + 1 }
  17. 万物皆对象, lambda 也不例外 lambda 也就是一个正常的对象 p l u s 1

    = - > ( x ) { x + 1 }
  18. 如果给这个lambda 一个引用, 我们可以跟用 method 一样用 p l u s 1

    = - > ( x ) { x + 1 } p l u s 1 . c a l l ( 3 ) p l u s 1 . ( 3 ) p l u s 1 [ 3 ]
  19. 三等公民 d e f p l u s 1 x

    x + 1 e n d [ 1 , 2 , 3 , 4 ] . m a p & p l u s 1 ` p l u s 1 ' : w r o n g n u m b e r o f a r g u m e n t s ( 0 f o r 1 ) ( A r g u m e n t E r r o r )
  20. 一等 vs 三等

  21. 一等公民 Proc p l u s 1 = - >

    ( x ) { x + 1 } [ 1 , 2 , 3 , 4 ] . m a p & p l u s 1
  22. 给三等座升个舱 d e f p l u s 1 x

    x + 1 e n d f i r s t _ c l a s s _ p l u s 1 = m e t h o d ( : p l u s 1 ) [ 1 , 2 , 3 , 4 ] . m a p & f i r s t _ c l a s s _ p l u s 1
  23. 升舱的魔法 # t o _ p r o c m

    e t h o d ( : p l u s 1 ) # = > # < M e t h o d : O b j e c t # p l u s 1 > c l a s s M e t h o d d e f t o _ p r o c l a m b d a { | * a r g s | s e l f . c a l l ( * a r g s ) } e n d e n d
  24. 升舱实例2 - Symbol % w ( o u y a

    n g j i c h a o ) . m a p & : c a p i t a l i z e # = = = % w ( o u y a n g j i c h a o ) . m a p { | x | x . c a p i t a l i z e }
  25. 来 Desugar & % w ( o u y a

    n g j i c h a o ) . m a p & : c a p i t a l i z e . t o _ p r o c % w ( o u y a n g j i c h a o ) . m a p & P r o c . n e w ( | x | x . s e n d ( : c a p i t a l i z e ) )
  26. 模式匹配 pattern matching

  27. destructure - 数组 f i r s t , *

    m i d d l e _ a n d _ l a s t = [ ' P h i l l i p ' , ' J a y ' , ' F r y ' ] " f i r s t : # { f i r s t } , m i d d l e _ a n d _ l a s t : # { m i d d l e _ a n d _ l a s t } "
  28. destructure - 哈希 方法的参数会自带 destructure 哈希的功能 aka k e y

    w o r d a r g u m e n t s : f r y = { f i r s t : ' P h i l l i p ' , m i d d l e : ' J a y ' , l a s t : ' F r y ' } d e f p r i n t F i r s t N a m e f i r s t : , * * r e s t p f i r s t , r e s t e n d p r i n t F i r s t N a m e f r y
  29. case when ruby 中的 case 可以搞定这几种模式匹配 值/ 表达式 类型 Proc

    正则
  30. 值 这个很简单,应该都有用过 m e = ' o u y a

    n g ' c a s e m e w h e n ' o u y a n g ' " h e h e # { m e } " e l s e ' h e h e j i c h a o ' e n d
  31. 类型 c l a s s M e d e

    f i n i t i a l i z e n a m e @ n a m e = n a m e e n d d e f h e h e d a " 呵呵哒 # { @ n a m e } " e n d e n d m e = M e . n e w ' o u y a n g ' c a s e m e w h e n M e m e . h e h e d a e l s e ' 呵呵哒了' e n d
  32. lambda (aka guard ) r e q u i r

    e ' o s t r u c t ' m e = O p e n S t r u c t . n e w ( n a m e : ' j i c h a o ' , f i r s t _ n a m e : ' o u y a n g ' ) c a s e m e w h e n - > ( w h o ) { w h o . n a m e = = ' j i c h a o ' } " h e h e # { m e } " e n d
  33. 正则 c a s e ' j i c h

    a o o u y a n g ' w h e n / o u y a n g / " 呵呵哒" e n d
  34. 但其实只是个简单的语法糖 case when 并不是magic ,其实只是 if else 的语法糖, 比如上面说的正则 i

    f ( / o u y a n g / = = = ' j i c h a o ' ) " h e h e d a " e n d 所以 magic 则是所有 when 的对象都实现了 = = = 方法而已 值: o b j e c t . = = = 会代理到 = = 类型: M o d u l e . = = = 会看是否是其 instance 正则: r e g e x . = = = 如果匹配返回 true 表达式:取决于表达式返回的值的 = = = 方法 lambda : p r o c . = = = 会运行 lambda 或者 proc
  35. 说了这么些奇技淫巧, 逼格还是不够高呀 除了花式一些有什么用呢? 纯 pure

  36. Category Theory Monad - 自函子范畴上的含幺半群

  37. 一个简单 把大象放冰箱里需要几步

  38. None
  39. None
  40. 命令式放大象 o p e n e d _ f r

    i d g e = o p e n _ f r i d g e i f o p e n e d _ f r i d g e f r i d g e _ w _ e l e p h e n t = p u t _ e l e p h e n t _ i n o p e n e d _ f r i d g e i f f r i d g e _ w _ e l e p h e n t c l o s e d _ f r i d g e = c l o s e _ f r i d g e i f c l o s e d _ f r i d g e ' y a y ' e l s e ' f a i l t o c l o s e f r i d g e ' e n d e l s e ' f a i l t o p u t e l e p h e n t i n ' e n d e l s e ' f a i l t o o p e n f r i d g e ' e n d
  41. 监控 o p e n e d _ f r

    i d g e = o p e n _ f r i d g e i f o p e n e d _ f r i d g e M o n i t o r i n g . l o g g e r . i n f o ( ' f r i d g e o p e n e d ' ) f r i d g e _ w _ e l e p h e n t = p u t _ e l e p h e n t _ i n o p e n e d _ f r i d g e i f f r i d g e _ w _ e l e p h e n t M o n i t o r i n g . l o g g e r . i n f o ( ' p u t e d a e l e p h e n t i n t o f r i d g e ' ) c l o s e d _ f r i d g e = c l o s e _ f r i d g e i f c l o s e d _ f r i d g e M o n i t o r i n g . l o g g e r . i n f o ( ' f r i d g e c l o s e d ' ) ' y a y ' e l s e M o n i t o r i n g . l o g g e r . e r r o r ( ' n o a b l e t o c l o s e f r i d g e ' ) ' f a i l t o c l o s e f r i d g e ' e n d e l s e M o n i t o r i n g . l o g g e r . e r r o r ( ' e l e p h e n t p u t f a i l e d ' ) ' f a i l t o p u t e l e p h e n t i n ' e n d e l s e M o n i t o r i n g . l o g g e r . e r r o r ( ' f a i l t o o p e n f r i d g e ' ) ' f a i l t o o p e n f r i d g e ' e n d
  42. 或者用更极端的抛异常方式 b e g i n c l o s

    e ( p u t _ e l e p h e n t _ i n o p e n _ f r i d g e ) r e s c u e A = > e . . . r e s c u e B = > e . . . r e s c u e C = > e . . . e n d
  43. 广告时间 ➡ ⬇ ↘ ⬇ ➡ 猫呢? https://git.io/cats.rb

  44. 让我们用一个简单的 Either Monad g e m i n s t

    a l l d a t a . e i t h e r r e q u i r e ' d a t a . e i t h e r ' R i g h t . n e w ( 1 ) . f l a t _ m a p d o | x | i f x < 1 L e f t . n e w ( ' m e h ' ) e l s e R i g h t . n e w ( x + 1 ) e n d e n d # = > # < R i g h t 2 >
  45. 来简化控制流 o p e n _ f r i d

    g e . f l a t _ m a p d o | f r i d g e | # < = 1 p u t _ e l e p h e n t _ i n f r i d g e # < = 2 e n d . f l a t _ m a p d o | f r i d g e | c l o s e f r i d g e # < = 3 e n d 这样可以专心构造控制逻辑, 而不需要关心上一步如果错误该怎么办
  46. 怎么做到的

  47. None
  48. Either 魔法 https://github.com/jcouyang/cats.rb/blob/master/lib/data.either.rb d e f f l a t

    _ m a p c a s e s e l f w h e n R i g h t y i e l d @ v e l s e s e l f e n d e n d
  49. 一个更实际的 用 microservices 组合成新的 service

  50. None
  51. None
  52. 上图有几次 IO 总共4 个IO, 每一步骤都可能出错 但程序猿不希望漏掉任何错误信息 但是又不能为了监控, 影响了这个简单的工作流

  53. 控制流不关心失败和监控 d o a < - f e t c

    h A b < - f e t c h B c < - p u t $ b l a h a + + b
  54. IO 自挂东南枝

  55. d e f f e t c h ( e

    n d p o i n t , d e c o d e r ) r e s p o n s e = s e l f . c l a s s . g e t ( e n d p o i n t , f o r m a t : : j s o n ) c a s e r e s p o n s e . c o d e w h e n 4 1 0 L e f t . n e w ( E x c e p t i o n s : : D a t a F a i l u r e . n e w ( " R e s o u r c e # { e n d p o i n t } w a s d e l e t e d " ) ) w h e n 4 0 4 L e f t . n e w ( E x c e p t i o n s : : D a t a F a i l u r e . n e w ( " R e s o u r c e # { e n d p o i n t } n o t e x i s t " ) ) w h e n 2 0 0 R i g h t . n e w d e c o d e r . f r o m _ j s o n ( r e s p o n s e . b o d y ) e l s e L e f t . n e w ( E x c e p t i o n s : : R e p o s i t o r y E r r o r . n e w ( " F e t c h i n g # { e n d p o i n t } w i t h E r r o r : \ n # { e n d p o i n t } , r e s p o n s e c o d e n d e n d
  56. f a i l u r e _ p r

    o c e s s e d , s u c c e s s _ p r o c e s s e d = E i t h e r . p a r t i t i o n M a p i n a t o r . r u n M o n i t o r i n g . s e n d _ p r o c e s s e d s u c c e s s _ p r o c e s s e d . l e n g t h M o n i t o r i n g . l o g g e r . i n f o ( " P r o c e s s e d s u c c e s s f u l # { s u c c e s s _ p r o c e s s e d . l e n g t h } l i s t i n g s : # { s u c c e s s _ p r o c e s s e d } M o n i t o r i n g . l o g g e r . e r r o r ( " P r o c e s s e d F A I L U R E # { f a i l u r e _ p r o c e s s e d . l e n g t h } w i t h E x c e p t i o n s : " ) u n l e s s f a i l u r e . . .
  57. 还可不可以在纯一些

  58. Free Monad aka Interpreter Pattern

  59. 有些像 Cons

  60. 还有... Coyoneda Free Monoid State EitherT MaybeT ...

  61. 这些我都不会讲...

  62. 因为我不会讲... 希望不久之后可以... g e m i n s t a

    l l c o n t r o l . m o n a d . f r e e
  63. Q/A

  64. 性能 你TM 都选 Ruby 了还在乎性能?

  65. 并发多线程 made easy r e q u i r e

    " c e l l u l o i d / a u t o s t a r t " m o d u l e E n u m e r a b l e d e f p m a p ( & b l o c k ) f u t u r e s = m a p { | e l e m | C e l l u l o i d : : F u t u r e . n e w ( e l e m , & b l o c k ) } f u t u r e s . m a p ( & : v a l u e ) e n d e n d
  66. 多谢 https://blog.oyanglul.us/functional-ruby.html https://github.com/jcouyang/cats.rb https://github.com/typelevel/cats http://hackage.haskell.org/package/base-4.8.1.0/docs/src/Data.Either.html https://wiki.haskell.org/Free_structure http://underscore.io/blog/posts/2015/04/23/deriving-the-free-monad.html http://underscore.io/blog/posts/2015/04/14/free-monads-are-simple.html https://www.coursera.org/learn/progfun2 https://www.amazon.com/Well-Grounded-Rubyist-David-Black/dp/1933988657

    https://mitpress.mit.edu/sicp