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

Demystifying functional programming and what that means for learning & teaching

Demystifying functional programming and what that means for learning & teaching

VIDEO: https://www.youtube.com/watch?v=2CWEg64qZnY (Sydney)

Did you ever wonder: Is functional programming hard? Do you have to be a math whiz? What about the jargon? This talk has answers.

Functional programming is sometimes perceived to be unapproachable, with unfamiliar jargon, obscure concepts, and bewildering theories. This seems counter to its main aim, namely to simplify programming and to make programming more widely accessible. In this talk, I like to argue that there is nothing inherently unapproachable or complex in functional programming, at least not beyond the complexity inherent in programming in general. Instead, we need to critically analyse our teaching strategies and ensure that they are appropriate for a broad range of developers. In my experience, the most common pitfalls are (1) to start with abstract concepts instead of with concrete examples and (2) confusing the historic development of a concept with a pedagogically appropriate teaching strategy. A good example of the latter problem is any attempt to explain the use of functors and monads in functional programming by appeal to category theory. Explaining an unfamiliar idea with an even more alien idea is generally a futile endeavour.

We avoid the first problem by leading with concrete examples, which we use to infer recurring patterns of computation and to motivate more abstract language features — for example, by demonstrating how higher-order functions facilitate the removal of duplicate code. We avoid the second problem by focusing on the concrete computational reasons for using a particular concept or language feature; that is, we place the why before the how. For instance, in sample code that requires maintaining shared state, a state transformer monad helps us to remove error-prone plumbing code.

Nevertheless, we have to acknowledge that moving from imperative, object-oriented programming to functional programming requires more effort than learning yet another object-oriented language. The key here is to clearly distinguish new concepts from known ideas that are just presented differently. Some concepts simply have different names (such as structs versus product types), some have different syntax (such as functional application without parenthesis in Haskell), and some are expressed differently (such as while loops versus tail recursive functions). In all cases, we can help learners by establishing a correspondence between the known and the superficially new.

Putting all of this together, teaching and learning functional programming is surprisingly straight forward. Still, we can do even better. Given the importance of working from examples and for students to experiment by quickly exploring a design space, ideas from live programming tighten the feedback loop and provide a distinct improvement for teaching over the classic REPL (read-eval-print loop) introduced with Lisp. I will demonstrate these improvements using Haskell playgrounds in the Haskell for Mac IDE, but the same applies to Swift playgrounds in Apple’s Xcode IDE and the Swift Playgrounds iPad app.

The material presented in this talk is informed by the experience that Gabriele Keller and I accumulated over a decade of teaching Haskell in a variety of courses at UNSW (University of New South Wales) to thousands of students spanning from absolute beginners to experienced developers in postgraduate courses. We experimented with a variety of approaches and performed student surveys to refine our approach over time. We wrote a textbook providing an introduction to computing for first years students and more recently an online Haskell tutorial including screencasts that feature live coding.

This talk was presented at four YOW! Nights in March 2018 in Sydney, Melbourne, Perth & Brisbane: http://nights.yowconference.com.au/archive-2018/yow-night-2018-sydney-manuel-chakravarty-mar-6/

2296a6bdc7779fe4017a23d268c8a79d?s=128

Manuel Chakravarty
PRO

March 06, 2018
Tweet

Transcript

  1. Manuel M T Chakravarty (Applicative & Tweag I/O) Gabriele Keller

    (UNSW Sydney) Demystifying Functional Programming And what that means for learning & teaching mchakravarty TacticalGrace justtesting.org haskellformac.com
  2. Structured Programming (1960s)

  3. Object-Oriented Programming (70s/80s)

  4. Functional Programming

  5. Functional Programming Too academic Impractical Too complicated Inefficient Not for

    the average developer
  6. Diffusion of Innovation [Everett Rogers 1962]

  7. None
  8. None
  9. None
  10. How do we get them on board?

  11. None
  12. None
  13. There is still time to submit proposals (deadline 18 March)!

  14. There is still time to submit proposals (deadline 18 March)!

  15. “How do we teach FP to the early majority as

    opposed to early adopters (and innovators).”
  16. http://learninghaskell.com

  17. Advise to The Innovator

  18. “Liberation from the tyranny of syntax: focus on concepts instead

    of language constructs.”
  19. “Liberation from the tyranny of syntax: focus on concepts instead

    of language constructs.” —Felleisen et al, The Structure and Interpretation of the Computer Science Curriculum
  20. Beware of Historical Explanations

  21. Beware of Historical Explanations Category Theory

  22. Beware of Historical Explanations Category Theory Formal Semantics

  23. Beware of Historical Explanations Category Theory Formal Semantics Functional Programming

  24. Beware of Historical Explanations “A monad is a monoid in

    the category of endofunctors.” Category Theory Formal Semantics Functional Programming
  25. Beware of Historical Explanations “A monad is a monoid in

    the category of endofunctors.” Category Theory Formal Semantics Functional Programming We need explanations that can stand on their own
  26. Mindset of The Early Adopter

  27. Examples First

  28. Examples First Why?

  29. Examples First Why? Example #1 Example #2 Example #n ộ

  30. Examples First Why? Example #1 Example #2 Example #n ộ

    Problem statement
  31. Examples First Why? Example #1 Example #2 Example #n ộ

    Problem statement Example solution ộ
  32. Examples First Why? Example #1 Example #2 Example #n ộ

    Problem statement General concept Example solution ộ
  33. Math Later

  34. Math Later “If math is useful to a functional programmer,

    functional programming must be able to motivate math.”
  35. Math Later “If math is useful to a functional programmer,

    functional programming must be able to motivate math.”
  36. But the Jargon is Here to Stay

  37. But the Jargon is Here to Stay Burrito Warm fuzzy

    thing Workflow Computation builder Kleisli triple
  38. But the Jargon is Here to Stay Burrito Warm fuzzy

    thing Workflow Computation builder Kleisli triple Monad
  39. Teaching The Early Majority

  40. None
  41. Examples first Generalise & abstract only after demonstrating a need

  42. Examples first Generalise & abstract only after demonstrating a need

    Teach design patterns FP abstractions are used in various idiomatic ways
  43. Examples first Generalise & abstract only after demonstrating a need

    Teach design patterns FP abstractions are used in various idiomatic ways Tight feedback loop Examples, stepwise evaluation, playgrounds
  44. Examples first Generalise & abstract only after demonstrating a need

    Teach design patterns FP abstractions are used in various idiomatic ways Tight feedback loop Examples, stepwise evaluation, playgrounds Visualisation can be an effective tool Pure computations lend themselves to visualisation
  45. Examples first Generalise & abstract only after demonstrating a need

    Teach design patterns FP abstractions are used in various idiomatic ways Tight feedback loop Examples, stepwise evaluation, playgrounds Visualisation can be an effective tool Pure computations lend themselves to visualisation
  46. Examples first Generalise & abstract only after demonstrating a need

  47. The Trouble with Recursion

  48. The Trouble with Recursion fix :: (a -> a) ->

    a fix f = let x = f x in x Simple. Elegant. Powerful.
  49. The Trouble with Recursion fix :: (a -> a) ->

    a fix f = let x = f x in x Simple. Elegant. Powerful. And utterly confusing…
  50. How does it work? How can I use it to

    solve a given problem?
  51. First Recursion Example natSum n 㱺 n + (n-1) +

    ⋯ + 2 + 1 + 0
  52. First Recursion Example natSum n 㱺 n + (n-1) +

    ⋯ + 2 + 1 + 0 natSum 0 = 0 natSum 1 = 1 + 0 natSum 2 = 2 + 1 + 0 natSum 3 = 3 + 2 + 1 + 0 natSum 4 = 4 + 3 + 2 + 1 + 0 natSum 5 = 5 + 4 + 3 + 2 + 1 + 0 ⋮
  53. First Recursion Example natSum n 㱺 n + (n-1) +

    ⋯ + 2 + 1 + 0 natSum 0 = 0 natSum 1 = 1 + 0 natSum 2 = 2 + 1 + 0 natSum 3 = 3 + 2 + 1 + 0 natSum 4 = 4 + 3 + 2 + 1 + 0 natSum 5 = 5 + 4 + 3 + 2 + 1 + 0 ⋮ we can reuse natSum 4
  54. First Recursion Example natSum n 㱺 n + (n-1) +

    ⋯ + 2 + 1 + 0 natSum 0 = 0 natSum 1 = 1 + natSum 0 natSum 2 = 2 + natSum 1 natSum 3 = 3 + natSum 2 natSum 4 = 4 + natSum 3 natSum 5 = 5 + natSum 4 ⋮
  55. First Recursion Example natSum n 㱺 n + (n-1) +

    ⋯ + 2 + 1 + 0 natSum 0 = 0 natSum 1 = 1 + natSum 0 natSum 2 = 2 + natSum 1 natSum 3 = 3 + natSum 2 natSum 4 = 4 + natSum 3 natSum 5 = 5 + natSum 4 ⋮ from here on all the same with different numbers
  56. First Recursion Example natSum n 㱺 n + (n-1) +

    ⋯ + 2 + 1 + 0 natSum 0 = 0 natSum n = n + natSum (n - 1)
  57. First Recursion Example natSum n 㱺 n + (n-1) +

    ⋯ + 2 + 1 + 0 natSum 0 = 0 natSum n = n + natSum (n - 1) use variable instead of unbound sequence
  58. natSum 0 = 0 natSum n = n + natSum

    (n - 1)
  59. natSum 0 = 0 natSum n = n + natSum

    (n - 1) natSum 5  㱺 5 + natSum (5 - 1)
  60. natSum 0 = 0 natSum n = n + natSum

    (n - 1) natSum 5  㱺 5 + natSum (5 - 1)        㱺 5 + natSum 4
  61. natSum 0 = 0 natSum n = n + natSum

    (n - 1) natSum 5  㱺 5 + natSum (5 - 1)        㱺 5 + natSum 4        㱺 5 + (4 + natSum (4 - 1))
  62. natSum 0 = 0 natSum n = n + natSum

    (n - 1) natSum 5  㱺 5 + natSum (5 - 1)        㱺 5 + natSum 4        㱺 5 + (4 + natSum (4 - 1))        㱺 5 + (4 + natSum 3)
  63. natSum 0 = 0 natSum n = n + natSum

    (n - 1) natSum 5  㱺 5 + natSum (5 - 1)        㱺 5 + natSum 4        㱺 5 + (4 + natSum (4 - 1))        㱺 5 + (4 + natSum 3)        㱺 5 + (4 + (3 + natSum (3 - 1)))
  64. natSum 0 = 0 natSum n = n + natSum

    (n - 1) natSum 5  㱺 5 + natSum (5 - 1)        㱺 5 + natSum 4        㱺 5 + (4 + natSum (4 - 1))        㱺 5 + (4 + natSum 3)        㱺 5 + (4 + (3 + natSum (3 - 1)))        㱺 5 + (4 + (3 + natSum 2))
  65. natSum 0 = 0 natSum n = n + natSum

    (n - 1) natSum 5  㱺 5 + natSum (5 - 1)        㱺 5 + natSum 4        㱺 5 + (4 + natSum (4 - 1))        㱺 5 + (4 + natSum 3)        㱺 5 + (4 + (3 + natSum (3 - 1)))        㱺 5 + (4 + (3 + natSum 2))        㱺 5 + (4 + (3 + (2 + natSum (2 - 1))))
  66. natSum 0 = 0 natSum n = n + natSum

    (n - 1) natSum 5  㱺 5 + natSum (5 - 1)        㱺 5 + natSum 4        㱺 5 + (4 + natSum (4 - 1))        㱺 5 + (4 + natSum 3)        㱺 5 + (4 + (3 + natSum (3 - 1)))        㱺 5 + (4 + (3 + natSum 2))        㱺 5 + (4 + (3 + (2 + natSum (2 - 1))))        㱺 5 + (4 + (3 + (2 + natSum 1)))
  67. natSum 0 = 0 natSum n = n + natSum

    (n - 1) natSum 5  㱺 5 + natSum (5 - 1)        㱺 5 + natSum 4        㱺 5 + (4 + natSum (4 - 1))        㱺 5 + (4 + natSum 3)        㱺 5 + (4 + (3 + natSum (3 - 1)))        㱺 5 + (4 + (3 + natSum 2))        㱺 5 + (4 + (3 + (2 + natSum (2 - 1))))        㱺 5 + (4 + (3 + (2 + natSum 1)))        㱺 5 + (4 + (3 + (2 + (1 + natSum (1 - 1)))))
  68. natSum 0 = 0 natSum n = n + natSum

    (n - 1) natSum 5  㱺 5 + natSum (5 - 1)        㱺 5 + natSum 4        㱺 5 + (4 + natSum (4 - 1))        㱺 5 + (4 + natSum 3)        㱺 5 + (4 + (3 + natSum (3 - 1)))        㱺 5 + (4 + (3 + natSum 2))        㱺 5 + (4 + (3 + (2 + natSum (2 - 1))))        㱺 5 + (4 + (3 + (2 + natSum 1)))        㱺 5 + (4 + (3 + (2 + (1 + natSum (1 - 1)))))        㱺 5 + (4 + (3 + (2 + (1 + natSum 0))))
  69. natSum 0 = 0 natSum n = n + natSum

    (n - 1) natSum 5  㱺 5 + natSum (5 - 1)        㱺 5 + natSum 4        㱺 5 + (4 + natSum (4 - 1))        㱺 5 + (4 + natSum 3)        㱺 5 + (4 + (3 + natSum (3 - 1)))        㱺 5 + (4 + (3 + natSum 2))        㱺 5 + (4 + (3 + (2 + natSum (2 - 1))))        㱺 5 + (4 + (3 + (2 + natSum 1)))        㱺 5 + (4 + (3 + (2 + (1 + natSum (1 - 1)))))        㱺 5 + (4 + (3 + (2 + (1 + natSum 0))))        㱺 5 + (4 + (3 + (2 + (1 + 0))))
  70. natSum 0 = 0 natSum n = n + natSum

    (n - 1) natSum 5  㱺 5 + natSum (5 - 1)        㱺 5 + natSum 4        㱺 5 + (4 + natSum (4 - 1))        㱺 5 + (4 + natSum 3)        㱺 5 + (4 + (3 + natSum (3 - 1)))        㱺 5 + (4 + (3 + natSum 2))        㱺 5 + (4 + (3 + (2 + natSum (2 - 1))))        㱺 5 + (4 + (3 + (2 + natSum 1)))        㱺 5 + (4 + (3 + (2 + (1 + natSum (1 - 1)))))        㱺 5 + (4 + (3 + (2 + (1 + natSum 0))))        㱺 5 + (4 + (3 + (2 + (1 + 0))))        㱺 15 natSum 5  㱺 5 + natSum (5 - 1)        㱺 5 + natSum 4        㱺 5 + (4 + natSum (4 - 1))        㱺 5 + (4 + natSum 3)        㱺 5 + (4 + (3 + natSum (3 - 1)))        㱺 5 + (4 + (3 + natSum 2))        㱺 5 + (4 + (3 + (2 + natSum (2 - 1))))        㱺 5 + (4 + (3 + (2 + natSum 1)))        㱺 5 + (4 + (3 + (2 + (1 + natSum (1 - 1)))))        㱺 5 + (4 + (3 + (2 + (1 + natSum 0))))        㱺 5 + (4 + (3 + (2 + (1 + 0))))        㱺 15
  71. Example-Driven Development Illustrates the concept (here recursion)

  72. Example-Driven Development Illustrates the concept (here recursion) Provides a concrete

    problem solving strategy (to get students started on their own code)
  73. Example-Driven Development Illustrates the concept (here recursion) Provides a concrete

    problem solving strategy (to get students started on their own code) Recursion
  74. Example-Driven Development Illustrates the concept (here recursion) Provides a concrete

    problem solving strategy (to get students started on their own code) Recursion Higher-order functions
  75. Example-Driven Development Illustrates the concept (here recursion) Provides a concrete

    problem solving strategy (to get students started on their own code) Recursion Higher-order functions Parametric polymorphism
  76. Example-Driven Development Illustrates the concept (here recursion) Provides a concrete

    problem solving strategy (to get students started on their own code) Recursion Higher-order functions Parametric polymorphism Type classes
  77. Example-Driven Development Illustrates the concept (here recursion) Provides a concrete

    problem solving strategy (to get students started on their own code) Recursion Higher-order functions Parametric polymorphism Type classes Categorial structures
  78. Example-Driven Development Illustrates the concept (here recursion) Provides a concrete

    problem solving strategy (to get students started on their own code) Recursion Higher-order functions Parametric polymorphism Type classes Categorial structures and more
  79. Examples first Generalise & abstract only after demonstrating a need

    Teach design patterns FP abstractions are used in various idiomatic ways Tight feedback loop Examples, stepwise evaluation, playgrounds Visualisation can be an effective tool Pure computations lend themselves to visualisation
  80. Teach design patterns FP abstractions are used in various idiomatic

    ways
  81. allSquares :: Num a => [a] -> [a] allSquares []

    = [] allSquares (x : xs) = x * x : allSquares xs
  82. allSquares :: Num a => [a] -> [a] allSquares []

    = [] allSquares (x : xs) = x * x : allSquares xs allToUpper :: String -> String allToUpper [] = [] allToUpper (chr : restString) = toUpper chr : allToUpper restString
  83. allSquares :: Num a => [a] -> [a] allSquares []

    = [] allSquares (x : xs) = x * x : allSquares xs allToUpper :: String -> String allToUpper [] = [] allToUpper (chr : restString) = toUpper chr : allToUpper restString
  84. allSquares :: Num a => [a] -> [a] allSquares []

    = [] allSquares (x : xs) = x * x : allSquares xs allToUpper :: String -> String allToUpper [] = [] allToUpper (chr : restString) = toUpper chr : allToUpper restString recursiveFunction [] = [] recursiveFunction (x : xs) = doSomethingWith x : recursiveFunction xs
  85. Computational Design Patterns Illustrates a computational idiom (here map-like recursion)

  86. Computational Design Patterns Illustrates a computational idiom (here map-like recursion)

    Provides learners with concrete guidance on how to get started
  87. Examples first Generalise & abstract only after demonstrating a need

    Teach design patterns FP abstractions are used in various idiomatic ways Tight feedback loop Examples, stepwise evaluation, playgrounds Visualisation can be an effective tool Pure computations lend themselves to visualisation
  88. Tight feedback loop Examples, stepwise evaluation, playgrounds

  89. None
  90. None
  91. Examples first Generalise & abstract only after demonstrating a need

    Teach design patterns FP abstractions are used in various idiomatic ways Tight feedback loop Examples, stepwise evaluation, playgrounds Visualisation can be an effective tool Pure computations lend themselves to visualisation
  92. Visualisation can be an effective tool Pure computations lend themselves

    to visualisation
  93. Pythagorean Trees

  94. Pythagorean Trees

  95. Pythagorean Trees

  96. Pythagorean Trees

  97. Pythagorean Trees

  98. Pythagorean Trees

  99. Pythagorean Trees

  100. None
  101. None
  102. None
  103. Properties Type Systems

  104. Are types restraints?

  105. Types are a design tool!

  106. None
  107. https://speakerdeck.com/mchakravarty/a-type-is-worth-a-thousand-tests YOW! Connected 2016, Melbourne

  108. “Doesn’t static typing hinder experimentation as you have to get

    everything right, before you can run it?”
  109. None
  110. None
  111. Improving Our Tools

  112. None
  113. Is this the best we can do?

  114. http://worrydream.com

  115. None
  116. Haskell for Mac

  117. Haskell for Mac

  118. Swift Playgrounds (iPad)

  119. mchakravarty TacticalGrace justtesting.org haskellformac.com

  120. natSum 0 = 0 natSum 1 = 1 + 0

    natSum 2 = 2 + 1 + 0 ⋮ Examples first mchakravarty TacticalGrace justtesting.org haskellformac.com
  121. natSum 0 = 0 natSum 1 = 1 + 0

    natSum 2 = 2 + 1 + 0 ⋮ Examples first recursiveFunction [] = [] recursiveFunction (x : xs) = doSomethingWith x : recursiveFunction xs Teach design patterns mchakravarty TacticalGrace justtesting.org haskellformac.com
  122. natSum 0 = 0 natSum 1 = 1 + 0

    natSum 2 = 2 + 1 + 0 ⋮ Examples first recursiveFunction [] = [] recursiveFunction (x : xs) = doSomethingWith x : recursiveFunction xs Teach design patterns Tight feedback loop & visualisation mchakravarty TacticalGrace justtesting.org haskellformac.com
  123. natSum 0 = 0 natSum 1 = 1 + 0

    natSum 2 = 2 + 1 + 0 ⋮ Examples first recursiveFunction [] = [] recursiveFunction (x : xs) = doSomethingWith x : recursiveFunction xs Teach design patterns Tight feedback loop & visualisation http://learninghaskell.com mchakravarty TacticalGrace justtesting.org haskellformac.com
  124. Thank you!

  125. Image Attribution https://pixabay.com/photo-1246043/ https://commons.wikimedia.org/wiki/File:Diffusion_of_ideas.svg https://web.archive.org/web/20140722064822/http://haskell.cs.yale.edu/people/paul-hudak/ https://commons.wikimedia.org/wiki/File:Robert_Harper.jpg https://commons.wikimedia.org/wiki/File:Rich_Hickey.jpg https://commons.wikimedia.org/wiki/File:Alan_Kay_(3097597186).jpg https://commons.wikimedia.org/wiki/File:Edsger_Wybe_Dijkstra.jpg https://harc.github.io/seymour-live2017/

    https://pixabay.com/photo-2536159/ https://pixabay.com/photo-1218797/ https://pixabay.com/photo-3195378/ https://pixabay.com/photo-2245832/ https://commons.wikimedia.org/wiki/File:Eugenio_Moggi.jpg https://commons.wikimedia.org/wiki/File:Wadler2.JPG https://commons.wikimedia.org/wiki/File:Handcuffs01_2008-07-27.jpg https://commons.wikimedia.org/wiki/File:Set_square_Geodreieck.svg https://www.flickr.com/photos/provisions/7986149891/