Demystifying Functional Programming

Demystifying Functional Programming

Because of some perceived complexities and the mathematical background in functional programming, the beginners get bogged down while learning and putting it into practice. As a matter of fact, few people give up after some initial attempts. But it is not as much harder as we think. It is just different!

Together, let's experience a different perspective of functional programming and get started in a better way 

C6dbbb399f7658917f60bd1e2a2663ed?s=128

Tamizhvendan S

May 29, 2018
Tweet

Transcript

  1. Demystifying Functional Programming tamizhvendan tamizhvendan Lead Consultant www.ajira.tech Tamizhvendan S

    Passionate, Pragmatic and Polyglot Programmer https://www.demystifyfp.com λ
  2. Why Functional Programming?

  3. Solution Problem

  4. Solution Problem

  5. Vehicle Influences The Journey

  6. Solution Problem

  7. Language Influences The Thinking

  8. int numbers[3] = {2,3,4}, squaredNumbers[3]; for (int i = 0;

    i < 3; i!++) { squaredNumbers[i] = numbers[i] * numbers[i]; }
  9. let numbers = [1,2,3]; let squaredNumbers = numbers.map(n !=> n

    * n);
  10. “A language that doesn’t affect the way you think about

    programming, is not worth knowing.” - Alan Perlis
  11. Solution Problem Challenges

  12. Domain Complexity Requirement Change Time To Market Reliability

  13. Solution Problem Abstractions

  14. Inheritance Encapsulation Polymorphism

  15. GoF Patterns!

  16. Inheritance Encapsulation Polymorphism GoF Patterns! Better Abstractions

  17. Functional Programming

  18. Solution Problem Better Abstractions

  19. FP Three Step Approach

  20. Step-1 Model The Domain (Data)

  21. “Data dominates. If you’ve chose the right data structures &

    organise things well, the algorithms will almost be self-evident. Data structures, not algorithms, are central to programming” - Rob Pike
  22. Step-2 Define The Behaviour (Algorithm)

  23. “Make each program do one thing well. To do a

    new job, build afresh rather than complicate the old programs by adding new “features”. Expect the output of every program to become the input of another, as yet unknown, program” - Unix Philosophy
  24. Step-3 Define The System (Composition)

  25. “Design is to take things apart in a such a

    way that they can be put back together” - Rich Hickey
  26. Separation of Concerns Composition

  27. Dynamic HTML Generation

  28. Step-1 Model The Domain (Data)

  29. type Attribute = { Name : string Value : string

    } <img src="cat.jpg" />
  30. <img src="cat.jpg" alt="cat" /> type Element = { Name :

    string Attributes : Attribute list }
  31. <p> This is a paragraph </p> type Element = {

    Name : string Attributes : Attribute list Content : Content } and Content = PlainText of string
  32. <textarea rows="4"> </textarea> type Element = { Name : string

    Attributes : Attribute list Content : Content option } and Content = PlainText of string
  33. <ul> <li>Coffee</li> <li>Tea</li> </ul> type Element = { Name :

    string Attributes : Attribute list Content : Content option } and Content = | PlainText of string | ChildElements of Element list
  34. Algebraic Data Types type Element = { Name : string

    Attributes : Attribute list Content : Content option } and Content = | PlainText of string | ChildElements of Element list Sum (or Choice) Type Product Type
  35. Step-2 Define The Behaviour

  36. Element !-> string let beveragesList = let content = childElements

    [ element "li" [] (plainText "Tea") element "li" [] (plainText "Coffee")] element "ul" [("class", "ulist")] content
  37. Step-3 Divide & Conquer (Compose)

  38. Attribute !-> string

  39. // Attribute  string let attrToHtmlStr attr = sprintf @"%s=""%s"""

    attr.Name attr.Value
  40. List<Attribute> !-> string

  41. List<Attribute> !-> string List<Attribute> !-> List<string> List<string> !-> string

  42. What we have What we want List<Attribute> !-> List<string> Attribute

    !-> string
  43. Map

  44. // List<Attribute>  List<string> let attrsToHtmlStr attrs = List.map attrToHtmlStr

    attrs (A !-> B) !-> List<A> !-> List<B> List.map
  45. What we have What we want List<string> !-> string string

    !-> List<string> !-> string String.concat
  46. Partial Application partially providing the argument(s) string !-> List<string> !->

    string
  47. string !-> List<string> !-> string String.concat <img src="cat.jpg" alt="cat" />

    String.concat " " string !-> List<string> !-> string
  48. What we have List<Attribute> !-> List<string> List<string> !-> string What

    we want List<Attribute> !-> string
  49. Expect the output of every program to become the input

    of another, as yet unknown, program” - Unix Philosophy
  50. A !-> B B !-> C A !-> C Function

    Composition
  51. Function Composition // List<Attribute>  string let attrsToHtmlStr = List.map

    attrToHtmlStr  String.concat " "
  52. Function Composition Using Piping // List<Attribute>  string let attrsToHtmlStr

    attrs = List.map attrToHtmlStr attrs  String.concat " "
  53. // List<Attribute>  string let attrsToHtmlStr attrs = attrs 

    List.map attrToHtmlStr  String.concat " " partial application
  54. let attrs = [ {Name = "src"; Value = "cat.jpg"}

    {Name = "alt"; Value = "cat"} ]
  55. Map (A !-> B) !-> List<A> !-> List<B> Partial Application

    string !-> List<string> !-> string Function Composition A !-> B B !-> C A !-> C
  56. Option<Content> !-> string

  57. Content !-> string

  58. Pattern Matching // Content  string let contentToHtmlStr content =

    match content with | PlainText x  x | ChildElements xs  xs  List.map elementToHtmlStr  String.concat ""
  59. What we have What we want Option<Content> !-> string Content

    !-> string
  60. Option<Content> !-> string Option<Content> !-> Option<string> Option<string> !-> string

  61. What we have What we want Content !-> string Option<Content>

    !-> Option<string>
  62. map

  63. map

  64. // Option<string> let contentOpt = element.Content  Option.map contentToHtmlStr

  65. let content = defaultArg contentOpt "" Option<string> !-> string core

    library function
  66. What we have What we want Element !-> string Option<Content>

    !-> string List<Attribute> !-> string
  67. let elementToHtmlStr element = let attrs = attrsToHtmlStr element.Attributes let

    contentOpt = element.Content  Option.map contentToHtmlStr let content = defaultArg contentOpt “" let tag = element.Name sprintf "<%s %s> %s </%s>" tag attrs content tag
  68. let beveragesList = let content = childElements [ element "li"

    [] (plainText "Tea") element "li" [] (plainText "Coffee")] element "ul" [("class", "ulist")] content
  69. Error Handling

  70. Result (Either) Type int !-> Result<Element, string>

  71. // int  Result<Element, string> let getElementById id = if

    id = 1 then Ok beveragesList else Error "unable to fetch"
  72. Transform Element to Html String after fetching

  73. What we have What we want Result<Element,string> !-> Result<string,string> Element

    !-> string
  74. map

  75. map

  76. // int  Result<int, int> let getHtmlStrById id = getElementById

    id  Result.map elementToHtmlStr
  77. map Preserves The Structure

  78. map Transforms The Value

  79. (A !-> B) !-> List<A> !-> List<B> map (A !->

    B) !-> Result<A,C> !-> Result<B,C> (A !-> B) !-> F<A> !-> F<B> (A !-> B) !-> Option<A> !-> Option<B>
  80. None
  81. Merging Elements! Element !-> Element !-> Element

  82. List<Attribute>  List<Attribute>  List<Attribute> Merging Attributes

  83. let mergeAttrs attrs1 attrs2 = attrs1 @ attrs2  List.groupBy

    (fun (a : Attribute)  a.Name)  List.map (fun (name, attrs)  let value = attrs  List.map (fun a  a.Value)  String.concat " " {Name = name; Value = value} )
  84. Content  Content  Content Merging Content

  85. let mergeContent content1 content2 = match content1, content2 with |

    PlainText x, PlainText y  sprintf "%s\n%s" x y  PlainText | ChildElements xs, ChildElements ys  ChildElements (xs @ ys) | _  content1
  86. What we have What we want Element !-> Element !->

    Element List<Attribute>  List<Attribute>  List<Attribute> Content  Content  Content
  87. type Element = { Name : string Attributes : Attribute

    list Content : Content option }
  88. What we have What we want Content  Content 

    Content Option<Content> !-> Option<Content> !-> Option<Content>
  89. aka map2 lift2

  90. let mergeElement e1 e2 = let attrs = mergeAttrs e1.Attributes

    e2.Attributes let content = Option.lift2 mergeContent e1.Content e2.Content { Name = e1.Name Attributes = attrs Content = content}
  91. Merge Elements after fetching Result<Element,string> !-> Result<Element,string> !-> Result<Element,string>

  92. What we have What we want Element  Element 

    Element Result<Element,string> !-> Result<Element,string> !-> Result<Element,string>
  93. lift2

  94. let getAndMergeElements e1Id e2Id = let e1R = getElementById e1Id

    let e2R = getElementById e2Id Result.lift2 mergeElement e1R e2R
  95. lift2

  96. A !-> B !-> C Option<A> !-> Option<B> !-> Option<C>

    lift2 Result<A,E> !-> Result<B,E> !-> Result<C,E> (A !-> B !-> C) !-> AP<A> !-> AP<B> !-> AP<C> List<A> !-> List<B> !-> List<C>
  97. map (A !-> B) !-> F<A> !-> F<B> lift2 (A

    !-> B !-> C) !-> AP<A> !-> AP<B> !-> AP<C>
  98. lift3 (A !-> B !-> C !-> D) !-> AP<A>

    !-> AP<B> !-> AP<C> !-> AP<D> liftN
  99. None
  100. Each Configuration Has Own Element Id type Configuration = {

    Id : int ElementId : int }
  101. Fetch Configuration And Then Fetch It’s Element

  102. Fetch Configuration int !-> Result<Configuration, string>

  103. // int  Result<Configuration, string> let getConfigurationById id = if

    id = 1 then Ok {Id = 1; ElementId = 1} else Error "unable to fetch"
  104. What we have What we want int !-> Result<Configuration, string>

    int !-> Result<Element, string> int !-> Result<Element, string> configuration id element id configuration id
  105. bind aka flatMap

  106. let getElementByConfigId cId = getConfigurationById cId  Result.bind (fun c

     getElementById c.ElementId)
  107. bind aka flatMap

  108. bind (A !-> M<B>) !-> M<A> !-> M<B> (A !->

    Result<B, C>) !-> Result<A,C> !-> Result<B, C> (A !-> List<B>) !-> List<A> !-> List<B> (A !-> Option<B>) !-> Option<A> !-> Option<B>
  109. map (A !-> B) !-> F<A> !-> F<B> lift2 (A

    !-> B !-> C) !-> AP<A> !-> AP<B> !-> AP<C> bind (A !-> M<B>) !-> M<A> !-> M<B>
  110. You can create your structure! FooBar<A> map lift2 bind

  111. Prompt<string> let namePrompt : Prompt<string> = stringPrompt "What's Your name?”

    > namePrompt();; What’s your name? Tamizhvendan val it : Result<string, PromptError> = Ok “Tamizhvendan”
  112. Prompt<int> let agePrompt : Prompt<int> = intPrompt "What's Your age?”

    > agePrompt();; What’s your age? 29 val it : Result<string, PromptError> = Ok 29 > agePrompt();; What’s your age? foobar val it : Result<string, PromptError> = Error ParserError
  113. let greeting name age = sprintf "Hey %s, you are

    %d years old!” name age let greetingWizard = lift2 greeting namePrompt agePrompt > greetingWizard();; What’s your name? Tamizhvendan What’s your age? 29 val it : Result<string, PromptError> = Ok “Hey Tamizhvendan, you are 29 years old!” lift2
  114. let addAgeBy10Years age = age + 10 let prankWizard =

    agePrompt |> map addAgeBy10Years |> lift2 greeting namePrompt > prankWizard();; What’s your name? Tamizhvendan What’s your age? 29 val it : Result<string, PromptError> = Ok “Hey Tamizhvendan, you are 39 years old!” map
  115. apply AP<(A !-> B)> !-> AP<A> !-> AP<B> append MO<A>

    !-> MO<A> !-> MO<A> fold (A !-> B !-> A) !-> A !-> FO<B> !-> A
  116. traverse (A !-> AP<B>) !-> T<A> !-> AP<T<B>> sequence T<AP<A>>

    !-> AP<T<A>>
  117. By The Way! M AP F Functor Applicative Monad *

    There are some laws!
  118. FP Demystified λ Algebraic Data Types λ Separate Pure &

    Impure Functions λ Function Signature Matters! λ map, liftN, bind, etc., λ Have Fun!! https://www.demystifyfp.com