Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

Dr Frankenfunctor and the Monadster

Dr Frankenfunctor and the Monadster

(Video available at http://fsharpforfunandprofit.com/monadster/)

You've got a pile of assorted functions lying around. Each one is useful and reliable, but they just don't fit together properly. How can you assemble them into a complete system that can stand on its own two feet and terrorize the local villagers?

In this session, I'll show how functional programming can transform all sorts of existing code into shapes that are plug-compatible and which can be bolted together effortlessly.

SAFETY NOTE: The techniques demonstrated are perfectly harmless and can even be used at your workplace -- no lightning bolts required.

Scott Wlaschin

October 15, 2015
Tweet

More Decks by Scott Wlaschin

Other Decks in Programming

Transcript

  1. Warning This talk contains: – gruesome topics – strained analogies

    – discussion of monads Not suitable for sensitive people (seriously)
  2. function A Input Output function B Input Output 1 Output

    2 function C Input 1 Output 1 Output 2 Input 2 function D Input 1 Output Input 2
  3. function A Input Output function B Input Output 1 Output

    2 function D Input 1 Output Input 2 How to compose?
  4. function A Input Output function B Input Output 1 Output

    2 function D Input 1 Output Input 2 How to compose?
  5. The spread of the monad • 1990 ACM Conference on

    LISP and Functional Programming First monad in captivity
  6. The spread of the monad • 1990 ACM Conference on

    LISP and Functional Programming • 1991 Eugenio Moggi, "Notions of computation and monads" • 1992 Philip Wadler, "Monads for Functional Programming" • 1999 Noel Winstanley, "What the hell are Monads?" • 2004 Greg Buchholz, "Monads in Perl" • 2005 Eric Kow, "Of monads and space suits" • 2006 Eric Kow, Monads as nuclear waste containers • 2009 James Iry, "A monad is just a monoid in the category of endofunctors, what's the problem?" • It’s everywhere now
  7. The spread of the monad • 1990 ACM Conference on

    LISP and Functional Programming • 1991 Eugenio Moggi, "Notions of computation and monads" • 1992 Philip Wadler, "Monads for Functional Programming" • 1999 Noel Winstanley, "What the hell are Monads?" • 2004 Greg Buchholz, "Monads in Perl" • 2005 Eric Kow, "Of monads and space suits" • 2006 Eric Kow, Monads as nuclear waste containers • 2009 James Iry, "A monad is just a monoid in the category of endofunctors, what's the problem?" • It’s everywhere now No wonder people think monads are dangerous
  8. The secret history of the monad • 1816 Dr Frankenfunctor

    creates the Monadster • 1990 ACM Conference on LISP and Functional Programming • 1991 Eugenio Moggi, "Notions of computation and monads" • 1992 Philip Wadler, "Monads for Functional Programming" • 1999 Noel Winstanley, "What the hell are Monads?" • 2004 Greg Buchholz, "Monads in Perl" • 2005 Eric Kow, "Of monads and space suits" • 2006 Eric Kow, Monads as nuclear waste containers • 2009 James Iry, "A monad is just a monoid in the category of endofunctors, what's the problem?" • And 100's more The topic of this talk
  9. The body was animated in a single instant, using a

    bolt of lightning to create the vital force.
  10. But how was it done? I have devoted many years

    of research into this matter...
  11. At last, I can reveal the secret techniques of Dr

    Frankenfunctor! Warning: These are powerful techniques and can be used for good or evil... I know of a young, innocent developer who was traumatized for life.
  12. Dr Frankenfunctor's toolbox 1. Modelling with pure functions 2. Wrapping

    a function in a type 3. Transforming parts into other parts 4. Combining two parts into one 5. Combining live and dead parts 6. Chaining “part-creating” functions together 7. A general way of combining any number of parts I don’t expect you to remember all this! Goal is just to demystify and give an overview
  13. Live body part Vital force Become alive! Remaining vital force

    Dead body part Less vital force available afterwards
  14. Live body part Vital force Become alive! Remaining vital force

    Dead body part No globals, no mutation!
  15. Live part B Vital force Become alive B! Remaining vital

    force Dead part B Live part A Vital force Become alive A! Remaining vital force Dead part A How to connect the force between two steps?
  16. Live part B Vital force Become alive B! Remaining vital

    force Dead part B Live part A Vital force Become alive A! Remaining vital force Dead part A How to combine the two outputs?
  17. Input A Uncurried Function Input B Output C Curried Function

    Input A Intermediate Function Output C Input B What is currying? after currying Currying means that *every* function has one input
  18. // naming a lambda Func<int,int> add1 = (y => 1

    + y) // using it var three = add1(2) Currying examples
  19. // naming a lambda let add1 = (fun y ->

    1 + y) // using it let three = add1 2 Currying examples
  20. // returning a lambda with baked in "x" let add

    x = (fun y -> x + y) // creating an intermediate function let add1 = add 1 // (fun y -> 1 + y) // using it let three = add1 2 Currying examples
  21. // "inlining" the intermediate function let three = (add 1)

    2 // returning a lambda with baked in "x" let add x = (fun y -> x + y) Currying examples
  22. // removing the parens let three = add 1 2

    Currying examples // returning a lambda with baked in "x" let add x = (fun y -> x + y)
  23. Become alive! Dead part A Vital force M<Live Part A>

    Live part A Wrapping the function "M" is for "Monadster"
  24. Become alive! Dead part A Vital force M<Live Part A>

    Live part A Wrapping the function
  25. Dead part A M<Live Part A> Create step in recipe

    Wrapping the function An "M-making" function Remember -- this is *not* a live part , it's a "potential" live part
  26. M<Live Part A> Run Live part A Remaining vital force

    Running the function Vital force
  27. M<Live Part A> Run Live part A Remaining vital force

    Running the function Vital force Become alive! Vital force Live part A M<Live Part A>
  28. let makeLiveThingM deadThing = // the inner one-argument function let

    becomeAlive vitalForceInput = ... do stuff ... return two outputs // wrap the inner function in the "M" wrapper M becomeAlive Creating M-things
  29. let makeLiveThingM deadThing = // get essence of dead thing

    let essence = getEssenceOfDeadThing deadThing // the inner one-argument function let becomeAlive vitalForceInput = // get a unit of vital force let unitOfForce, remainingForce = getVitalForce vitalForce // create a live thing let liveThing = new LiveThing(essence, unitOfForce) // return the live thing and remaining force (liveThing, remainingVitalForce) // return a pair // wrap the inner function in the "M" wrapper M becomeAlive Creating M-things
  30. let makeLiveThingM deadThing = // get essence of dead thing

    let essence = getEssenceOfDeadThing deadThing // the inner one-argument function let becomeAlive vitalForceInput = // get a unit of vital force let unitOfForce, remainingForce = getVitalForce vitalForce // create a live thing let liveThing = new LiveThing(essence, unitOfForce) // return the live thing and remaining force (liveThing, remainingVitalForce) // return a pair // wrap the inner function in the "M" wrapper M becomeAlive Creating M-things
  31. let makeLiveThingM deadThing = // get essence of dead thing

    let essence = getEssenceOfDeadThing deadThing // the inner one-argument function let becomeAlive vitalForceInput = // get a unit of vital force let unitOfForce, remainingForce = getVitalForce vitalForce // create a live thing let liveThing = new LiveThing(essence, unitOfForce) // return the live thing and remaining force (liveThing, remainingVitalForce) // return a pair // wrap the inner function in the "M" wrapper M becomeAlive Creating M-things
  32. let makeLiveThingM deadThing = // get essence of dead thing

    let essence = getEssenceOfDeadThing deadThing // the inner one-argument function let becomeAlive vitalForceInput = // get a unit of vital force let unitOfForce, remainingForce = getVitalForce vitalForce // create a live thing let liveThing = new LiveThing(essence, unitOfForce) // return the live thing and remaining force (liveThing, remainingVitalForce) // return a pair // wrap the inner function in the "M" wrapper M becomeAlive Creating M-things
  33. let makeLiveThingM deadThing = // get essence of dead thing

    let essence = getEssenceOfDeadThing deadThing // the inner one-argument function let becomeAlive vitalForceInput = // get a unit of vital force let unitOfForce, remainingForce = getVitalForce vitalForce // create a live thing let liveThing = new LiveThing(essence, unitOfForce) // return the live thing and remaining force (liveThing, remainingVitalForce) // return a pair // wrap the inner function in the "M" wrapper M becomeAlive Creating M-things
  34. let makeLiveThingM deadThing = // get essence of dead thing

    let essence = getEssenceOfDeadThing deadThing // the inner one-argument function let becomeAlive vitalForceInput = // get a unit of vital force let unitOfForce, remainingForce = getVitalForce vitalForce // create a live thing let liveThing = new LiveThing(essence, unitOfForce) // return the live thing and remaining force (liveThing, remainingVitalForce) // return a pair // wrap the inner function in the "M" wrapper M becomeAlive Creating M-things makeLiveThingM : DeadThing -> M<LiveThing>
  35. // create DeadLeftLeg let deadLeftLeg = DeadLeftLeg "Boris" // create

    a M<LiveLeftLeg> let leftLegM = makeLiveLeftLegM deadLeftLeg // potential leg only! // now pretend that vital force is available let vf = {units = 10} // make a real left leg by running leftLegM let liveLeftLeg, remainingForce = runM leftLegM vf // output: // liveLeftLeg : LiveLeftLeg = // LiveLeftLeg ("Boris",{units = 1}) // remainingForce : VitalForce = {units = 9} Demo – Left Leg
  36. Healing a broken arm Live Healed Arm Live Broken Arm

    HealBrokenArm We have this function!
  37. Live Healed Arm ...But we want one of these! How

    can we get it? Healing a broken arm Dead Broken Arm We have one of these...
  38. Create Dead Broken Arm Dead Healed Arm Live Healed Arm

    Healing a broken arm HealBrokenArm
  39. Create Dead Broken Arm Dead Healed Arm Live Healed Arm

     No. We can only heal live arms Healing a broken arm HealBrokenArm
  40. Dead Broken Arm Live Healed Arm Live Broken Arm Create

    HealBrokenArm Healing a broken arm
  41. Dead Broken Arm Live Healed Arm Live Broken Arm Create

    HealBrokenArm No. We can't create live things directly, only M-type things  Healing a broken arm 
  42. Dead Broken Arm M<Live Healed Arm>  M<Live Broken Arm>

    Create HealBrokenArm No. "HealBrokenArm" doesn't work on M-type things  Healing a broken arm
  43. Dead Broken Arm M<Live Healed Arm> M<Live Broken Arm> Create

    HealBrokenArmM We need a special "HealBrokenArmM" that works on M-type things   Where can we get it from? Healing a broken arm
  44. Live Healed Arm Live Broken Arm HealBrokenArm Healing a broken

    arm M<Live Healed Arm> M<Live Broken Arm> HealBrokenArmM This is what we’ve got This is what we want
  45. Live Healed Arm Live Broken Arm HealBrokenArm Healing a broken

    arm M<Live Healed Arm> M<Live Broken Arm> HealBrokenArmM map
  46. "map" is generic for M-things Normal World a b map

    World of M<_> things M<a> M<b> A function in the world of M-things “lifting”
  47. let map f bodyPartM = // the inner one-argument function

    let becomeAlive vitalForce = // get the input body part by running the M-thing let bodyPart,remainingVitalForce = runM bodyPartM vitalForce // transform the body part using the function let transformedBodyPart = f bodyPart // return the transformed part and remaining force (transformedBodyPart, remainingVitalForce) // wrap the inner function in the "M" wrapper M becomeAlive Transformation function M-thing to transform
  48. let map f bodyPartM = // the inner one-argument function

    let becomeAlive vitalForce = // get the input body part by running the M-thing let bodyPart,remainingVitalForce = runM bodyPartM vitalForce // transform the body part using the function let transformedBodyPart = f bodyPart // return the transformed part and remaining force (transformedBodyPart, remainingVitalForce) // wrap the inner function in the "M" wrapper M becomeAlive
  49. let map f bodyPartM = // the inner one-argument function

    let becomeAlive vitalForce = // get the input body part by running the M-thing let bodyPart,remainingVitalForce = runM bodyPartM vitalForce // transform the body part using the function let transformedBodyPart = f bodyPart // return the transformed part and remaining force (transformedBodyPart, remainingVitalForce) // wrap the inner function in the "M" wrapper M becomeAlive
  50. let map f bodyPartM = // the inner one-argument function

    let becomeAlive vitalForce = // get the input body part by running the M-thing let bodyPart,remainingVitalForce = runM bodyPartM vitalForce // transform the body part using the function let transformedBodyPart = f bodyPart // return the transformed part and remaining force (transformedBodyPart, remainingVitalForce) // wrap the inner function in the "M" wrapper M becomeAlive
  51. let map f bodyPartM = // the inner one-argument function

    let becomeAlive vitalForce = // get the input body part by running the M-thing let bodyPart,remainingVitalForce = runM bodyPartM vitalForce // transform the body part using the function let transformedBodyPart = f bodyPart // return the transformed part and remaining force (transformedBodyPart, remainingVitalForce) // wrap the inner function in the "M" wrapper M becomeAlive
  52. let map f bodyPartM = // the inner one-argument function

    let becomeAlive vitalForce = // get the input body part by running the M-thing let bodyPart,remainingVitalForce = runM bodyPartM vitalForce // transform the body part using the function let transformedBodyPart = f bodyPart // return the transformed part and remaining force (transformedBodyPart, remainingVitalForce) // wrap the inner function in the "M" wrapper M becomeAlive map : ('a -> 'b ) -> // The input is a normal function. ( M<'a> -> M<'b> ) // The output is a function in the // world of M-things.
  53. let deadLeftBrokenArm = DeadLeftBrokenArm "Victor" let leftBrokenArmM = makeLiveLeftBrokenArm deadLeftBrokenArm

    let leftHealedArmM = // map the healing function to the world of M-things let healBrokenArmM = map healBrokenArm // use it! healBrokenArmM leftBrokenArmM // return type is M<LiveLeftHealedArm> // run the M<LiveLeftHealedArm> with some vital force let liveLeftHealedArm, remainingAfterLeftArm = runM leftHealedArmM vf Demo – Broken Arm
  54. let deadLeftBrokenArm = DeadLeftBrokenArm "Victor" let leftBrokenArmM = makeLiveLeftBrokenArm deadLeftBrokenArm

    let leftHealedArmM = // map the healing function to the world of M-things let healBrokenArmM = map healBrokenArm // use it! healBrokenArmM leftBrokenArmM // return type is M<LiveLeftHealedArm> // run the M<LiveLeftHealedArm> with some vital force let liveLeftHealedArm, remainingAfterLeftArm = runM leftHealedArmM vf Demo – Broken Arm
  55. let deadLeftBrokenArm = DeadLeftBrokenArm "Victor" let leftBrokenArmM = makeLiveLeftBrokenArm deadLeftBrokenArm

    let leftHealedArmM = // map the healing function to the world of M-things let healBrokenArmM = map healBrokenArm // use it! healBrokenArmM leftBrokenArmM // return type is M<LiveLeftHealedArm> // run the M<LiveLeftHealedArm> with some vital force let liveLeftHealedArm, remainingAfterLeftArm = runM leftHealedArmM vf Demo – Broken Arm // output // liveLeftHealedArm : LiveLeftHealedArm = // LiveLeftHealedArm ("Victor",{units = 1}) // remainingAfterLeftArm : VitalForce = // {units = 9}
  56. The "map" pattern for elevated worlds map Elevated World Normal

    World a b Elevated World Normal World E<a> E<b> A function in the world of normal things where "elevated world" is Option, List, Async, etc
  57. The "map" pattern for elevated worlds map Elevated World Normal

    World a b Elevated World Normal World E<a> E<b> A function in the world of E-things where "elevated world" is Option, List, Async, etc
  58. The importance of map World of normal values int string

    bool World of Lists List<int> List<string> List<bool>
  59. The importance of map  World of normal values int

    string bool World of Lists List<int> List<string> List<bool>
  60. The importance of map  World of normal values int

    string bool World of Lists List<int> List<string> List<bool>
  61. let addTwo_L inputList = let outputList = new List() foreach

    element in inputList do let newElement = addTwo element outputList.Add(newElement) How not to code with lists Let’s say you have some ints wrapped in an List, and you want to add 2 to each element: let addTwo x = x + 2
  62. let addTwo_L inputList = let outputList = new List() foreach

    element in inputList do let newElement = addTwo element outputList.Add(newElement) How not to code with lists Let’s say you have some ints wrapped in an List, and you want to add 2 to each element: let addTwo x = x + 2
  63. let addTwo_L inputList = let outputList = new List() foreach

    element in inputList do let newElement = addTwo element outputList.Add(newElement) How not to code with lists Let’s say you have some ints wrapped in an List, and you want to add 2 to each element: let addTwo x = x + 2 
  64. How not to code with lists addTwo  World of

    normal values World of Lists
  65. How to code with lists T -> U List<T> ->

    List<U> List.map World of normal values World of Lists Linq.Select
  66. How to code with lists addTwo addTwo_L [1;2] |> 1

    |> // 3 // [3;4] World of normal values World of Lists
  67. // map works with "addTwo" let addTwo_L = List.map addTwo

    // List<int> -> List<int> addTwo_L [1;2] // List<int> = [3; 4] [1;2] |> List.map addOne // List<int> = [3; 4] // map works with "healBrokenArm" let healBrokenArm_L = List.map healBrokenArm // List<LiveLeftBrokenArm> -> List<LiveLeftHealedArm> Same applies for any generic type: Option, Task, etc
  68. Combining two parts Dead Lower Arm Dead Upper Arm Live

    Whole Arm What we've got What we want
  69. Combining two parts Live Arm Live Lower Arm ArmSurgery Live

    Whole Arm Live Upper Arm We have this function!
  70. Live Arm ...and we want one of these! How can

    we get it? Combining two parts Dead Lower Arm We have these... Dead Upper Arm
  71. Live Arm Combining two parts Dead Lower Arm Dead Upper

    Arm Dead Arm Create  No. Only works on live arms ArmSurgery
  72. Create ArmSurgery Combining two parts Dead Lower Arm Dead Upper

    Arm Live Lower Arm Live Upper Arm Live Arm Create
  73.  Create ArmSurgery No. We can't make live things directly,

    only M-type things  Combining two parts Dead Lower Arm Dead Upper Arm Live Lower Arm Live Upper Arm Live Arm Create
  74.  Create ArmSurgery  Combining two parts Dead Lower Arm

    Dead Upper Arm M<LiveLowerArm> M<LiveUpperArm> M<LiveArm> Create No. "ArmSurgery" doesn't work on M-type things 
  75. Create ArmSurgeryM  Combining two parts Dead Lower Arm Dead

    Upper Arm M<LiveLowerArm> M<LiveUpperArm> M<LiveArm> Create We need a special "ArmSurgeryM" that works on M-type things  
  76. Combining two parts map2 ArmSurgery Live Lower Arm Live Upper

    Arm Live Arm ArmSurgeryM M<LiveLowerArm> M<LiveUpperArm> M<LiveArm>
  77. World of things World of M<_> things Param1 -> Param2

    -> Result map2 A 2-param function in the world of things The "map2" pattern for M-things
  78. A 2-param function in the world of M<thing>s World of

    things World of M<_> things Param1 -> Param2 -> Result M<Param1> -> M<Param2> -> M<Result> map2 The "map2" pattern for M-things
  79. A 2-param function in the world of E<thing>s World of

    things World of E<_> things Param1 -> Param2 -> Result E<Param1> -> E<Param2> -> E<Result> map2 The "map2" pattern for elevated worlds Applies to any generic type: Option, Task, etc
  80. Create HeadSurgery Combining mismatched parts Dead Brain Empty Head Live

    Brain Empty Head Live Head Copy  No. We can't make live things directly, only M-type things
  81. Create HeadSurgeryM  Combining mismatched parts Dead Brain Empty Head

    M<Live Brain> M<Empty Head> So what goes here? M<Live Head> This is not a live thing
  82. Create HeadSurgeryM  Combining mismatched parts Dead Brain M<Live Brain>

    M<Empty Head> M<Live Head> return Empty Head Both are M-things now
  83. Create HeadSurgeryM  Combining mismatched parts Dead Brain M<Live Brain>

    M<Empty Head> M<Live Head> map2 Empty Head Live Head Live Brain HeadSurgery Empty Head return
  84. "return" for M-things return Normal World a World of M<_>

    things A value in the world of normal things
  85. "return" for M-things return Normal World a World of M<_>

    things M<a> A value in the world of M-things
  86. "return" for all elevated worlds return Normal World a Elevated

    World E<a> A value in the world of normal things A value in the world of E-things
  87. Chaining functions Dead Heart M<Live Heart> Live Heart M<Beating Heart>

    We have an M-generating function We have another M-generating function
  88. Dead Heart M<Live Heart>  Live Heart M<Beating Heart> 

     Chaining functions Output type doesn't match input type
  89. Dead Heart M<Live Heart>  M<Live Heart> M<Beating Heart> 

    Chaining functions If we could change this type to M<Live Heart>, it would work! 
  90. M<Beating Heart> M<Live Heart> makeBeatingHeartM M<Beating Heart> Live Heart makeBeatingHeart

    Chaining functions This is what we’ve got: an M-generating function This is what we want: an M-thing only function
  91. M<Beating Heart> M<Live Heart> makeBeatingHeartM M<Beating Heart> Live Heart makeBeatingHeart

    Chaining functions bind "bind" converts an M-generating function into a M-thing only function
  92. "bind" for M-things bind World of M<_> things Normal World

    a M<b> World of M<_> things Normal World M<a> M<b> an M-generating function (diagonal)
  93. "bind" for M-things bind World of M<_> things Normal World

    a M<b> World of M<_> things Normal World M<a> M<b> a pure M-thing function (horizontal)
  94. let makeLiveHeart deadHeart = let becomeAlive vitalForce = // snipped

    (liveHeart, remainingVitalForce) M becomeAlive // signature // makeLiveHeart : DeadHeart -> M<LiveHeart> Demo: Chaining
  95. let makeBeatingHeart liveHeart = let becomeAlive vitalForce = // snipped

    (beatingHeart, remainingVitalForce) M becomeAlive // signature // makeBeatingHeart : LiveHeart -> M<BeatingHeart> Demo: Chaining
  96. let beatingHeartM = // Convert "diagonal" to "horizontal" let makeBeatingHeartM

    = bind makeBeatingHeart // flow the data through each function DeadHeart "Anne" // DeadHeart |> makeLiveHeart // output = M<LiveHeart> |> makeBeatingHeartM // output = M<BeatingHeart> Demo: Chaining Q: Where did the vital force tracking go? A: We are silently threading data through the code. But no globals, no mutables!
  97. // run the M<BeatingHeart> with some vital force let beatingHeart,

    remainingFromHeart = runM beatingHeartM vf // val beatingHeart : BeatingHeart = // BeatingHeart ( // LiveHeart ("Anne",{units = 1}), // {units = 1} ) // // val remainingFromHeart : VitalForce = // {units = 8} // TWO units used up! Demo: Chaining Proof that we are silently threading the vital force through the code!
  98. "bind" for all elevated worlds bind Elevated World Normal World

    a E<b> Elevated World Normal World E<a> E<b> where "elevated world" is Option, List, Async, etc
  99. "bind" for all elevated worlds bind Elevated World Normal World

    a E<b> Elevated World Normal World E<a> E<b> where "elevated world" is Option, List, Async, etc
  100. The importance of bind World of normal values int string

    bool World of Lists List<int> List<string> List<bool> "Diagonal" functions
  101. The importance of bind World of normal values int string

    bool World of Lists List<int> List<string> List<bool> Bind "SelectMany“ in C#
  102. The importance of bind World of normal values int string

    bool World of Lists List<int> List<string> List<bool> Bind
  103. The importance of bind World of normal values int string

    bool World of Lists List<int> List<string> List<bool> Bind
  104. The importance of bind  World of normal values int

    string bool World of Lists List<int> List<string> List<bool> “Horizontal" functions
  105. type LiveBody = { leftLeg: LiveLeftLeg rightLeg : LiveLeftLeg leftArm

    : LiveLeftHealedArm rightArm : LiveRightArm head : LiveHead heart : BeatingHeart } Defining the whole body
  106. val createBody : leftLeg :LiveLeftLeg -> rightLeg :LiveLeftLeg -> leftArm

    :LiveLeftHealedArm -> rightArm :LiveRightArm -> head :LiveHead -> beatingHeart :BeatingHeart -> LiveBody // final result Creating the whole body Do we need a "mapSix" function?
  107. Introducing "apply" apply World of M<_> things M<(a->b)> World of

    M<_> things M<a> M<b> apply M<(a->b->c)> M<a> M<b->c>
  108. Introducing "apply" apply World of M<_> things M<(a->b)> World of

    M<_> things M<a> M<b> apply M<(a->b->c)> M<a> M<b->c> apply M<(a->b->c->d)> M<a> M<b->c->d>
  109. Using "apply" to make "map3" apply M<(b->c->d)> M<b> M<c->d> M<c->d>

    apply M<c> M<d> apply M<(a->b->c->d)> M<a> M<b->c->d>
  110. Using "apply" to make "map3" apply M<(a->b->c->d)> M<a> M<b> M<c>

    a->b->c->Result a b c Result return create create create apply apply
  111. Using "apply" to make "map3" apply M<(a->b->c->d)> M<a> M<b> M<c>

    M<Result> a->b->c->Result a b c Result return create create create apply apply
  112. // create the body in the "normal" world let createBody

    leftLeg rightLeg leftArm rightArm head heart = { leftLeg = leftLeg rightLeg = rightLeg leftArm = leftArm rightArm = rightArm head = head heart = heart } Demo: Whole body
  113. // <*> means "apply" let bodyM = returnM createBody <*>

    leftLegM <*> rightLegM <*> leftHealedArmM <*> rightArmM <*> headM <*> beatingHeartM // output is M<LiveBody> Demo: Whole body M-Things from earlier Output is still a potential thing. We're "programming"!
  114. // Lightning strikes! It's alive! let liveBody, remainingFromBody = runM

    bodyM vf // val liveBody : LiveBody = // {leftLeg = LiveLeftLeg ("Boris",{units = 1}) // rightLeg = LiveLeftLeg ("Boris",{units = 1}) // leftArm = LiveLeftArm ("Victor",{units = 1}) // rightArm = {lowerArm = LiveRightLowerArm // ("Tom",{units = 1}) // upperArm = LiveRightUpperArm // ("Jerry",{units = 1}) } // head = {brain = LiveBrain // ("Abby Normal",{units = 1}) // emptyHead = EmptyHead "Yorick"} // heart = BeatingHeart ( // LiveHeart ("Anne",{units = 1}), // {units = 1})} // val remainingFromBody : VitalForce = {units = 2} Demo: Whole body The state is automatically kept up-to-date
  115. Live part B Vital force Become alive B! Remaining vital

    force Dead part B Live part A Vital force Become alive A! Remaining vital force Dead part A Connect the force between two steps using "bind" or "apply"
  116. Live part B Vital force Become alive B! Remaining vital

    force Dead part B Live part A Vital force Become alive A! Remaining vital force Dead part A Combine two outputs using "map2"
  117. The Functional Toolbox • "map" – Lifts functions into the

    elevated world • "return" – Lifts values into the elevated world • "apply" – Lets you combine elevated values – "map2" is a just a specialized "apply“ • "bind" – Converts “diagonal” functions into horizontal ones
  118. The Functional Toolbox • "map" – (with a sensible implementation)

    is a Functor • "return" and "apply" – (with a sensible implementation) is an Applicative • "return" and "bind" – (with a sensible implementation) is a Monad
  119. let beatingHeartM = DeadHeart "Anne" |> makeLiveHeart |> makeBeatingHeartM //

    TWO units of force used up State monad Where is the "vital force" tracking variable?
  120. let bodyM = returnM createBody <*> leftLegM <*> rightLegM <*>

    leftHealedArmM <*> rightArmM <*> headM <*> beatingHeartM // EIGHT units of force used up State monad Where is the "vital force" variable? We are silently threading the vital force through the code... ...which allows us to focus on the design instead
  121. Using Dr Frankenfunctor's techniques in the real world Is this

    too academic? Too abstract to be useful?
  122. Scenario: Update user information • Input is {userId, name, email}

    • Step 1: Validate input – Could fail if name is blank, etc • Step 2: Canonicalize input – Trim blanks, lowercase email, etc • Step 3: Fetch existing record from db – Could fail if record is missing • Step 4: Update record in db
  123. Validate Canonicalize DbFetch DbUpdate Generates a possible error Generates a

    possible error Always succeeds Doesn't return How can we glue these mismatched functions together?
  124. Summary • We've seen a toolkit of useful techniques –

    Don’t expect to understand them all straight away. • How to wrap a function into a type – A.k.a. a "computation" or "effect“ • How to use "map", "apply" and "bind" – Monads are not that scary – You can work with effects before running them! • How to thread state "invisibly" through code – Without using any globals or mutables!