Monads you've already put in production (without knowing it)

Monads you've already put in production (without knowing it)

9245f8593dc19a394a021ea0f17f9e0f?s=128

Tejas Dinkar

October 10, 2014
Tweet

Transcript

  1. Monads you are already using in prod Tejas Dinkar nilenso

  2. about.me • Hi, I’m Tejas • Nilenso: Partner • twitter:

    tdinkar • github: gja
  3. Serious Pony

  4. Online Abuse

  5. Trouble at the Koolaid Point http://seriouspony.com/trouble-at-the-koolaid-point/ https://storify.com/adriarichards/telling-my-troll-story-because- kathy-sierra-left-t

  6. If you think you understand Monads, you don't understand Monads.

  7. None
  8. This talk is inaccurate and will make a mathematician cry

  9. None
  10. Goal of this talk For you to say “Oh yeah,

    I’ve used that hack”
  11. None
  12. Monads • Programmable Semicolons • Used to hide plumbing away

    from you • You can say Monads in almost any sentence and people will think you are smart
  13. None
  14. Values Value

  15. Monads Value Box

  16. Mysore Masala Monad M onad Value

  17. Monads Value Box

  18. Monads • Monads define two functions • return takes a

    value and puts it in a box • bind takes a box & function f, returning f(value) • it is expected that the function returns a box
  19. Value Value Another Value Value Function return bind

  20. Our Function Signatures Value f(value)

  21. Some math (√4) + 5

  22. Some math (√4) + 5 3 or 7!

  23. Value 4

  24. Monad [4]

  25. [alive, dead]

  26. ruby! x = [1, 2, 3] y = x.map {

    |x| x + 1 } # y = [2, 3, 4]
  27. return Value Value return

  28. return def m_return(x) [x] end # m_return(4) => [4]

  29. The functions Value f(value)

  30. Square Root fn def sqrt(x) s = Math.sqrt(x) [s, -s]

    end # sqrt(4) => [2, -2]
  31. Increment Fn def inc_5(x) [x + 5] end # inc_5(1)

    => [6]
  32. Bind Functions Another Value Value Function bind

  33. Bind Function x = m_return(4) y = x.????? { |p|

    sqrt(p) } # I want [-2, 2]
  34. Bind Function x = m_return(4) y = x.map {|p| sqrt(p)

    } # y => [[2, -2]] # ^—— Box in a box?
  35. Bind Function x = m_return(4) y = x.mapcat {|p| sqrt(p)

    } # y => [2, -2]
  36. Putting it together m_return(4) .mapcat {|p| sqrt(p)} .mapcat {|p| inc_5(p)}

    # => [3, 7]
  37. You have invented the List Monad, used to model non-determinism

    Congrats
  38. Turtles all the way down

  39. A small constraint • Let’s do a bit of a

    self imposed constraint on this • Functions must return either 0 or 1 elements • (we’ll only model positive integers here)
  40. return - stays the same

  41. bind - stays the same x = m_return(4) y =

    x.mapcat { |p| inc_5(p) } # y => 9
  42. Square Root Fn def sqrt(x) if (x < 0) return

    [] #error else [Math.sqrt(x)] end end # sqrt(4) => [2] # sqrt(-1) => []
  43. Describe in English There is a list passed to each

    step Maybe this list has just one element, or Maybe it has none
  44. None
  45. The Maybe Monad • The intent is to short circuit

    computation • The value of the `box’ is None, or Just(Value) • You can think of it as a type-safe nil / null
  46. try def try(x, f) if x == nil return f(x)

    else return nil end end # 4.try { |x| x + 5 } => 9 # nil.try {|x| x + 5 } => nil
  47. None
  48. Let’s start over • The Monad Laws • Left Identity

    • Right Identity • Associativity
  49. Left Identity m_return(a).bind(f) == f(a)

  50. Right Identity m.bind(m_return) == m

  51. Associativity m.bind(f).bind(g) == m.bind(x -> f(x).bind(g))

  52. Store Computation

  53. The State Monad • Rest of the world - State

    Machine (sorta) • The value inside the box f(state) => [r new-state] • Particularly useful in pure languages like Haskell • Let’s build a stack
  54. The functions Value f(value)

  55. The functions (f(value) state) [new-value, new-state]

  56. push def push(val) lambda { |state| new_state = state.push(val) [value,

    new_state] } end
  57. pop def pop() lambda { |state| val = state.pop() [val,

    state] } end
  58. def double_top() lambda { |state| top = state.pop() [2 *

    top, state.push(2*top)] } end double_top
  59. return def m_return(x) lambda { |state| [x, state] } end

  60. bind def bind(mv, f) lambda { |state| v, temp_state =

    mv(state) state_fn = f(v) state_fn(temp_state) } end
  61. example # Not working code ! m_return(4) .bind(a -> push(a))

    .bind(b -> push(b + 1)) .bind(c -> double_top()) .bind(d -> sum_top2()) .bind(e -> pop())
  62. None
  63. Associativity m.bind(f).bind(g) == m.bind(x => f(x).bind(g))

  64. turn this # Not working code ! m_return(4) .bind(a ->

    push(a)) .bind(b -> push(b + 1)) .bind(c -> double_top()) .bind(d -> sum_top2()) .bind(e -> pop())
  65. into this m_return(4) .bind(a -> push(a) .bind(b -> push(b +

    1) .bind(c -> double_top() .bind(d -> sum_top() .bind(e -> pop())))))
  66. done with ruby

  67. imagine # Not working code state_monad { a <- m_return(4)

    b <- push(a) c <- push(b + 1) d <- double_top() e <- sum_top2() pop() }
  68. Back to List m_return(4) .mapcat {|p| sqrt(p)} .mapcat {|p| inc_5(p)}

    # => [3, 7]
  69. Back to List m_return(4) .mapcat {|a| sqrt(a) .mapcat {|b| inc_5(b)}}

    # => [3, 7]
  70. Back to List list_monad { a <- m_return(4) b <-

    sqrt(a) c <- inc_5(b) c }
  71. On to Clojure • this is an example from clojure.net

    • the state is a vector containing every function we’ve called so far
  72. (defn inc-s [x] (fn [state] [(inc x) (conj state :inc)]))

  73. in clojure (defn inc-s [x] (fn [state] [(inc x) (conj

    state :inc)])) (defn do-things [x] (domonad state-m [a (inc-s x) b (double-s a) c (dec-s b) d (dec-s c)] d)) ! ((do-things 7) []) => [14 [:inc :double :dec :dec]]
  74. state monad in Clojure (defmonad state-m "Monad describing stateful computations.

    The monadic values have the structure (fn [old-state] [result new-state])." [m-result (fn m-result-state [v] (fn [s] [v s])) m-bind (fn m-bind-state [mv f] (fn [s] (let [[v ss] (mv s)] ((f v) ss)))) ])
  75. state monad in Haskell inc = state (\st -> let

    st' = st +1 in (st’,st')) inc3 = do x <- inc y <- inc z <- inc return z
  76. Finally, IO

  77. IOMonad • rand-int(100) is non deterministic !

  78. ay-yo

  79. IOMonad • rand-int(100) is non deterministic • rand-int(100, seed =

    42) is deterministic • monadic value: f(world) => [value, world-after-io]
  80. IOMonad • puts() just `appends to a buffer’ in the

    real world • How does gets() return different strings? • gets() returns a fixed value based on the `world’
  81. Image Credits http://www.myfoodarama.com/2010/11/masala- dosa.html http://www.clojure.net/2012/02/10/State/ http://www.cafepress.com/ +no_place_like_home_ruby_slippers_3x5_area_rug, 796646161 http://www.netizens-stalbans.co.uk/installs-and- upgrades.html.htm

    http://www.hpcorporategroup.com/what-is-the-life- box.html
  82. Thank You MANY QUESTIONS? VERY MONAD SO FUNCTIONAL Y NO

    CLOJURE? TEJAS@GJA.IN @tdinkar WOW WOW WOW MUCH EASY SUPER SIMPLE