Getting Started in Functional Programming using F#

Getting Started in Functional Programming using F#

Solving complex problems with less code is the beauty of functional programming. But for programmers who are coming from imperative or object-oriented programming background, it is very hard to think from a different perspective and follow the design principles of functional programming.

Functional Programming is not as hard as you think. This talk will help you to demystify the perceived complexities of functional programming and empower you to get started in functional programming using F#.

Meetup: http://www.meetup.com/Chennai-Microsoft-Azure-User-Group/events/235035148/

C6dbbb399f7658917f60bd1e2a2663ed?s=128

Tamizhvendan S

November 19, 2016
Tweet

Transcript

  1. Functional Programming λ

  2. None
  3. About Me Pragmatic, Passionate and Polyglot Programmer @tamizhvendan http://blog.tamizhvendan.in www.ajira.tech

    bit.ly/fsapplied
  4. May I Know about you?

  5. Why another Programming Language?

  6. Problem

  7. Problem Solution

  8. Problem Solution

  9. Origin

  10. Origin Destination

  11. Origin Destination

  12. Origin Destination

  13. Origin Destination

  14. Origin Destination

  15. Origin Destination

  16. Origin Destination

  17. Problem

  18. Problem Solution

  19. Problem Solution

  20. Problem Solution C#

  21. Problem Solution C# F#

  22. Problem Solution C# F# Java

  23. Problem Solution C# F# Java js

  24. Problem Solution C# F# Java js Azure

  25. Problem Solution C# F# Java js Azure Aws

  26. Problem Solution C# F# Java js Azure Aws GCE

  27. Why Functional Programming?

  28. None
  29. None
  30. I’m Convinced! Tell me How to go about it?

  31. Functional Programming x Model your Domain (Data)

  32. Functional Programming λx Define functions which operate on your Domain

    (Data)
  33. Functional Programming >> >=> >>= << |> Define “System” by

    composing functions
  34. POST /message Chat Server CREATE Model Your Domain x

  35. POST /message Chat Server CREATE Model Your Domain HttpRequest x

  36. POST /message Chat Server CREATE Model Your Domain HttpRequest Message

    x
  37. POST /message Chat Server CREATE Model Your Domain HttpRequest Message

    Error x
  38. POST /message Chat Server CREATE Model Your Domain HttpRequest Message

    Error Result<Message,Error> x
  39. POST /message Chat Server CREATE Model Your Domain HttpRequest Message

    Error Result<Message,Error> HttpResponse x
  40. POST /message Chat Server CREATE Define functions λx

  41. POST /message Chat Server CREATE Define functions readRequest :: HttpRequest

    -> Result<Message,Error> λx
  42. POST /message Chat Server CREATE Define functions readRequest :: HttpRequest

    -> Result<Message,Error> validate :: Message -> Result<Message,Error> λx
  43. POST /message Chat Server CREATE Define functions readRequest :: HttpRequest

    -> Result<Message,Error> validate :: Message -> Result<Message,Error> createInDb :: Message -> Result<Message,Error> λx
  44. POST /message Chat Server CREATE Define functions readRequest :: HttpRequest

    -> Result<Message,Error> validate :: Message -> Result<Message,Error> createInDb :: Message -> Result<Message,Error> writeResponse :: Result<Message,Error> -> HttpResponse λx
  45. POST /message Chat Server CREATE Compose functions

  46. POST /message Chat Server CREATE Compose functions readRequest

  47. POST /message Chat Server CREATE Compose functions readRequest >>= createInDb

  48. POST /message Chat Server CREATE Compose functions readRequest >>= validate

    >>= createInDb
  49. POST /message Chat Server CREATE Compose functions readRequest >>= validate

    >>= createInDb |> writeResponse
  50. POST /message Chat Server CREATE Compose functions readRequest system ::

    HttpRequest -> HttpResponse >>= validate >>= createInDb |> writeResponse
  51. Let’s Apply!

  52. Libraries & Frameworks For Web Development

  53. Learn By Synthesis

  54. Learn By Synthesis http://www.keyword-suggestions.com/

  55. Learn By Synthesis http://www.keyword-suggestions.com/

  56. Learn By Synthesis Don’t dissect the frog, build it! http://www.keyword-suggestions.com/

  57. Learn By Synthesis Don’t dissect the frog, build it! http://www.keyword-suggestions.com/

    http://bit.ly/29QAUyp
  58. Domain User sends a Request and gets a Response after

    some time Request contains HttpMethod, Headers & a Resource Path HttpMethod will be any one of Get, Post, Put, Delete Headers is a list of Key Value pairs Path specifies the path of the resource being requested
  59. Domain Response contains StatusCode, Headers & Content StatusCode will be

    any one of Ok, NotFound, BadRequest Headers is a list of Key Value pairs Content represents resource that is requested.
  60. Functional Programming x Model your Domain (Data)

  61. Model HttpMethod HttpMethod will be one of the following Get,

    Put, Post, Delete
  62. type HttpMethod = | Get | Put | Delete |

    Post
  63. Model Header Header is a name value pair

  64. type Header = string * string

  65. Model Request Request contains HttpMethod, Path, Headers

  66. type Request = { Path : string Headers : Header

    list HttpMethod : HttpMethod }
  67. Model StatusCode StatusCode will be one of the following Ok,

    NotFound, BadRequest
  68. type StatusCode = | Ok | BadRequest | NotFound

  69. Model Response Response contains StatusCode, Headers & Content

  70. type Response = { Content : string Headers : Header

    list StatusCode : StatusCode }
  71. Designing Handlers express.js ASP.NET Web API Message Handler Go Spark

    Java
  72. Design For Composition

  73. Design For Composition x f1 y y f2 z >>

    x f1 >> f2 z
  74. Design For Composition x f1 y y f2 z >>

    x f1 >> f2 z req handler1 res
  75. Design For Composition x f1 y y f2 z >>

    x f1 >> f2 z req handler1 res req handler2 res
  76. Design For Composition x f1 y y f2 z >>

    x f1 >> f2 z req handler1 res req handler2 res
  77. Design For Composition x f1 y y f2 z >>

    x f1 >> f2 z req handler1 res req handler2 res
  78. Design For Composition x f1 y y f2 z >>

    x f1 >> f2 z req handler1 res req handler2 res >>
  79. Design For Composition x f1 y y f2 z >>

    x f1 >> f2 z req handler1 res req handler2 res >>
  80. Design For Composition x f1 y y f2 z >>

    x f1 >> f2 z req handler1 res req handler2 res >>
  81. Design For Composition x f1 y y f2 z >>

    x f1 >> f2 z req handler1 res req handler2 res >> x
  82. Design For Composition x f1 y y f2 z >>

    x f1 >> f2 z req handler1 res req handler2 res >> x Create a new type containing Request & Response
  83. Model Context Context contains Request & Response x

  84. type Context = { Request : Request Response : Response

    }
  85. C handler1 C C handler2 C Design For Composition

  86. C handler1 C C handler2 C If handler1 handle the

    req don’t invoke handler2 Choose either one of the handler Invoke handler2 always Design For Composition
  87. Design For Composition

  88. C handler1 Design For Composition

  89. C handler1 Design For Composition

  90. C handler1 Design For Composition C handler2

  91. C handler1 Design For Composition C handler2 C

  92. C handler1 Design For Composition C handler2 C C handler3

  93. C handler1 Design For Composition C handler2 C C handler3

    C
  94. Async POST /message Chat Server CREATE

  95. Async POST /message Chat Server CREATE OK Chat Server Inserted

  96. Design For Composition Async Type Option Type

  97. C handler1 Design For Composition Async Type Option Type

  98. C handler1 Design For Composition Async Type Option Type

  99. C handler1 Design For Composition C handler2 Async Type Option

    Type
  100. C handler1 Design For Composition C handler2 C Async Type

    Option Type
  101. C handler1 Design For Composition C handler2 C handler3 C

    Async Type Option Type
  102. C handler1 Design For Composition C handler2 C handler3 C

    C Async Type Option Type
  103. Model WebPart WebPart takes a context and asynchronously may return

    the (modified) context.
  104. type WebPart = Context -> Async<Context option>

  105. Functional Programming λx Define functions which operate on your Domain

    (Data)
  106. Combinator Pattern type WebPart = Context -> Async<Context option>

  107. Combinator Pattern

  108. Combinator Pattern The application is a

  109. Combinator Pattern The application is a list of WebParts

  110. Combinator Pattern The application is a list of WebParts Combined

    together
  111. Combinator Pattern The application is a list of WebParts Combined

    together in some order
  112. Combinator Pattern type WebPart = Context -> Async<Context option> The

    application is a list of WebParts Combined together in some order
  113. Combinator Pattern type WebPart = Context -> Async<Context option> functions

    that create WebPart The application is a list of WebParts Combined together in some order
  114. Combinator Pattern type WebPart = Context -> Async<Context option> functions

    that create WebPart The application is a list of WebParts Combined together in some order functions that combine WebParts
  115. Combinators type WebPart = Context -> Async<Context option>

  116. Combinators type WebPart = Context -> Async<Context option> functions that

    create WebPart
  117. Combinators type WebPart = Context -> Async<Context option> functions that

    create WebPart combinator<‘a> : ‘a -> WebPart
  118. Define OK Combinator OK is a combinator that takes a

    string and returns a WebPart It modifies the Response’s Content field with the string passed and sets its StatusCode field to Ok Then it asynchronously returns the modified context as Optional type string -> WebPart string -> Context -> Async<Context option>
  119. let OK content ctx = let response = {ctx.Response with

    StatusCode = Ok Content = content} {ctx with Response = response} |> Some |> async.Return
  120. Let’s Test

  121. Define NOT_FOUND Combinator NOT_FOUND is a combinator that takes a

    string and returns a WebPart It modifies the Response’s Content field with the string passed and sets its StatusCode field to NotFound Then it asynchronously returns the modified context as Optional type string -> WebPart string -> Context -> Async<Context option>
  122. let NOT_FOUND content ctx = let response = {ctx.Response with

    StatusCode = NotFound Content = content} {ctx with Response = response} |> Some |> async.Return
  123. Define BAD_REQUEST Combinator BAD_REQUEST is a combinator that takes a

    string and returns a WebPart It modifies the Response’s Content field with the string passed and sets its StatusCode field to BadRequest Then it asynchronously returns the modified context as Optional type string -> WebPart string -> Context -> Async<Context option>
  124. let BAD_REQUEST content ctx = let response = {ctx.Response with

    StatusCode = BadRequest Content = content} {ctx with Response = response} |> Some |> async.Return
  125. Let’s Test

  126. Filters

  127. C handler1 Filters

  128. C handler1 Filters

  129. C handler1 C handler2 Filters

  130. C handler1 C handler2 C Filters

  131. Define GET Filter GET verifies the HttpMethod of the context’s

    Request It asynchronously returns the context as Optional Type, if it is Get else asynchronously returns None Context -> Async<Context option>
  132. let GET ctx = match ctx.Request.HttpMethod = Get with |

    true -> Some ctx |> async.Return | _ -> None |> async.Return
  133. Define POST Filter POST verifies the HttpMethod of the context’s

    Request It asynchronously returns the context as Optional Type, if it is Post else asynchronously returns None Context -> Async<Context option>
  134. let POST ctx = match ctx.Request.HttpMethod = Post with |

    true -> Some ctx |> async.Return | _ -> None |> async.Return
  135. Define PUT Filter PUT verifies the HttpMethod of the context’s

    Request It asynchronously returns the context as Optional Type, if it is Put else asynchronously returns None Context -> Async<Context option>
  136. let PUT ctx = match ctx.Request.HttpMethod = Put with |

    true -> Some ctx |> async.Return | _ -> None |> async.Return
  137. Define DELETE Filter DELETE verifies the HttpMethod of the context’s

    Request It asynchronously returns the context as Optional Type, if it is Delete else asynchronously returns None Context -> Async<Context option>
  138. let DELETE ctx = match ctx.Request.HttpMethod = Delete with |

    true -> Some ctx |> async.Return | _ -> None |> async.Return
  139. Let’s Test

  140. Define Path Filter Path takes a string and verifies it

    for equality with the Path of the context’s Request It asynchronously returns the context as Optional Type, if the path matches else asynchronously returns None string -> Context -> Context option
  141. let Path path ctx = match ctx.Request.Path = path with

    | true -> ctx |> Some |> async.Return | _ -> None |> async.Return
  142. Let’s Test

  143. Functional Programming >> >=> >>= << |> Define “System” by

    composing functions
  144. Function Composition

  145. Function Composition x f1 y y f2 z >> x

    f1 >> f2 z
  146. Function Composition x f1 y y f2 z >> x

    f1 >> f2 z x f1 y y f2 z >>x f1 >> f2 >> f3 z z f3 a
  147. Function Composition

  148. Function Composition

  149. Function Composition None

  150. Function Composition C None

  151. Function Composition C Some<C> None

  152. Function Composition C Some<C> None

  153. Function Composition Async<None> C Some<C> None

  154. Function Composition Async<None> C Some<C> None C

  155. Function Composition Async<None> Async<Some<C>> C Some<C> None C

  156. Function Composition Async<None> Async<Some<C>> C Some<C> None type WebPart =

    Context -> Async<Context option> C
  157. Function Composition Async<None> Async<Some<C>> C Some<C> None type WebPart =

    Context -> Async<Context option> C C WebPart C
  158. Function Composition Async<None> Async<Some<C>> C Some<C> None type WebPart =

    Context -> Async<Context option> C C WebPart C C WebPart
  159. Function Composition Async<None> Async<Some<C>> C Some<C> None type WebPart =

    Context -> Async<Context option> C C WebPart C C WebPart C WebPart C
  160. Function Composition Async<None> Async<Some<C>> C Some<C> None type WebPart =

    Context -> Async<Context option> C C WebPart C C WebPart C WebPart C C WebPart C
  161. Function Composition Async<None> Async<Some<C>> C Some<C> None type WebPart =

    Context -> Async<Context option> C C WebPart C C WebPart C WebPart C C WebPart C C WebPart C
  162. Function Composition Async<None> Async<Some<C>> C Some<C> None type WebPart =

    Context -> Async<Context option> >> C C WebPart C C WebPart C WebPart C C WebPart C C WebPart C
  163. Function Composition Async<None> Async<Some<C>> C Some<C> None type WebPart =

    Context -> Async<Context option> >> C C WebPart C C WebPart C WebPart C C WebPart C C WebPart C
  164. Async in F# // Async<int> let count = async.Return 5

    let count = async {return 5} // Async<int> -> Async<uint> let printAsync asyncContent = async { let! content = asyncContent printfn "%d" content } // calling async functions printAsync count |> Async.RunSynchronously
  165. Async in F# // Async<int> let count = async.Return 5

    let count = async {return 5} // Async<int> -> Async<uint> let printAsync asyncContent = async { let! content = asyncContent printfn "%d" content } // calling async functions printAsync count |> Async.RunSynchronously
  166. Async in F# // Async<int> let count = async.Return 5

    let count = async {return 5} // Async<int> -> Async<uint> let printAsync asyncContent = async { let! content = asyncContent printfn "%d" content } // calling async functions printAsync count |> Async.RunSynchronously
  167. Async in F# // Async<int> let count = async.Return 5

    let count = async {return 5} // Async<int> -> Async<uint> let printAsync asyncContent = async { let! content = asyncContent printfn "%d" content } // calling async functions printAsync count |> Async.RunSynchronously
  168. Async in F# // Async<int> let count = async.Return 5

    let count = async {return 5} // Async<int> -> Async<uint> let printAsync asyncContent = async { let! content = asyncContent printfn "%d" content } // calling async functions printAsync count |> Async.RunSynchronously
  169. Async in F# // Async<int> let count = async.Return 5

    let count = async {return 5} // Async<int> -> Async<uint> let printAsync asyncContent = async { let! content = asyncContent printfn "%d" content } // calling async functions printAsync count |> Async.RunSynchronously
  170. Async in F# // Async<int> let count = async.Return 5

    let count = async {return 5} // Async<int> -> Async<uint> let printAsync asyncContent = async { let! content = asyncContent printfn "%d" content } // calling async functions printAsync count |> Async.RunSynchronously C
  171. Async in F# // Async<int> let count = async.Return 5

    let count = async {return 5} // Async<int> -> Async<uint> let printAsync asyncContent = async { let! content = asyncContent printfn "%d" content } // calling async functions printAsync count |> Async.RunSynchronously C
  172. Async in F# // Async<int> let count = async.Return 5

    let count = async {return 5} // Async<int> -> Async<uint> let printAsync asyncContent = async { let! content = asyncContent printfn "%d" content } // calling async functions printAsync count |> Async.RunSynchronously C C
  173. Option in F# // int option let age = Some

    25 let ageNotGiven = None // int option -> unit let printOption value = match value with | Some v -> printfn "%d" v | None -> printfn "<EMPTY>" printOption age printOption ageNotGiven
  174. Option in F# // int option let age = Some

    25 let ageNotGiven = None // int option -> unit let printOption value = match value with | Some v -> printfn "%d" v | None -> printfn "<EMPTY>" printOption age printOption ageNotGiven
  175. Option in F# // int option let age = Some

    25 let ageNotGiven = None // int option -> unit let printOption value = match value with | Some v -> printfn "%d" v | None -> printfn "<EMPTY>" printOption age printOption ageNotGiven C
  176. Option in F# // int option let age = Some

    25 let ageNotGiven = None // int option -> unit let printOption value = match value with | Some v -> printfn "%d" v | None -> printfn "<EMPTY>" printOption age printOption ageNotGiven C
  177. Option in F# // int option let age = Some

    25 let ageNotGiven = None // int option -> unit let printOption value = match value with | Some v -> printfn "%d" v | None -> printfn "<EMPTY>" printOption age printOption ageNotGiven C C
  178. Option in F# // int option let age = Some

    25 let ageNotGiven = None // int option -> unit let printOption value = match value with | Some v -> printfn "%d" v | None -> printfn "<EMPTY>" printOption age printOption ageNotGiven C C
  179. Option in F# // int option let age = Some

    25 let ageNotGiven = None // int option -> unit let printOption value = match value with | Some v -> printfn "%d" v | None -> printfn "<EMPTY>" printOption age printOption ageNotGiven C C
  180. Option in F# // int option let age = Some

    25 let ageNotGiven = None // int option -> unit let printOption value = match value with | Some v -> printfn "%d" v | None -> printfn "<EMPTY>" printOption age printOption ageNotGiven C C
  181. Option in F# // int option let age = Some

    25 let ageNotGiven = None // int option -> unit let printOption value = match value with | Some v -> printfn "%d" v | None -> printfn "<EMPTY>" printOption age printOption ageNotGiven C C
  182. Option in F# // int option let age = Some

    25 let ageNotGiven = None // int option -> unit let printOption value = match value with | Some v -> printfn "%d" v | None -> printfn "<EMPTY>" printOption age printOption ageNotGiven C C
  183. Composing WebParts

  184. >=> C w1 C C w2 C C w1 Composing

    WebParts
  185. >=> C w1 C C w2 C C w1 Composing

    WebParts
  186. >=> C w1 C C w2 C C w1 type

    WebPart = Context -> Async<Context option> Composing WebParts
  187. >=> C w1 C C w2 C C w1 type

    WebPart = Context -> Async<Context option> Composing WebParts
  188. >=> C w1 C C w2 C C w1 type

    WebPart = Context -> Async<Context option> Composing WebParts OK C C content string -> Context -> Async<Context option>
  189. >=> C w1 C C w2 C C w1 type

    WebPart = Context -> Async<Context option> Composing WebParts OK C C content string -> Context -> Async<Context option> function that create WebPart
  190. >=> C w1 C C w2 C C w1 type

    WebPart = Context -> Async<Context option> Composing WebParts OK C C content string -> Context -> Async<Context option> compose C C w1 w2 WebPart -> WebPart -> Context -> Async<Context option> function that create WebPart
  191. >=> C w1 C C w2 C C w1 type

    WebPart = Context -> Async<Context option> Composing WebParts OK C C content string -> Context -> Async<Context option> compose C C w1 w2 WebPart -> WebPart -> Context -> Async<Context option> function that create WebPart function that combine WebParts
  192. compose C C w1 w2

  193. compose C C w1 w2 let compose w1 w2 ctx

    = async { return Some ctx }
  194. compose C C w1 w2

  195. compose C C w1 w2 Let’s go inside compose

  196. compose C C w1 w2 let compose w1 w2 ctx

    = async { return Some ctx } Let’s go inside compose
  197. compose C C w1 w2 let compose w1 w2 ctx

    = async { return Some ctx } Let’s go inside compose
  198. compose C C w1 w2 let compose w1 w2 ctx

    = async { return Some ctx } let! result = w1 ctx Let’s go inside compose
  199. compose C C w1 w2 let compose w1 w2 ctx

    = async { return Some ctx } let! result = w1 ctx C w1 C Let’s go inside compose
  200. compose C C w1 w2 let compose w1 w2 ctx

    = async { return Some ctx } let! result = w1 ctx C w1 C Let’s go inside compose
  201. compose C C w1 w2 let compose w1 w2 ctx

    = async { return Some ctx } let! result = w1 ctx C w1 C C Let’s go inside compose
  202. compose C C w1 w2 C w1 C C

  203. compose C C w1 w2 let compose w1 w2 ctx

    = async { let! result = w1 ctx return Some ctx } C w1 C C
  204. compose C C w1 w2 let compose w1 w2 ctx

    = async { let! result = w1 ctx return Some ctx } C w1 C C
  205. compose C C w1 w2 let compose w1 w2 ctx

    = async { let! result = w1 ctx return Some ctx } C w1 C C match result with | Some c -> () | None -> ()
  206. compose C C w1 w2 let compose w1 w2 ctx

    = async { let! result = w1 ctx return Some ctx } C w1 C C match result with | Some c -> () | None -> () C C
  207. compose C C w1 w2 C w1 C C C

    C
  208. compose C C w1 w2 let compose w1 w2 ctx

    = async { let! result = w1 ctx match result with | Some c -> | None -> } C w1 C C C C
  209. compose C C w1 w2 let compose w1 w2 ctx

    = async { let! result = w1 ctx match result with | Some c -> | None -> } C w1 C C C C
  210. compose C C w1 w2 let compose w1 w2 ctx

    = async { let! result = w1 ctx match result with | Some c -> | None -> } C w1 C C C C let! result = w2 c return result return None
  211. compose C C w1 w2 let compose w1 w2 ctx

    = async { let! result = w1 ctx match result with | Some c -> | None -> } C w1 C C C C let! result = w2 c return result return None w2 C
  212. compose C C w1 w2 let compose w1 w2 ctx

    = async { let! result = w1 ctx match result with | Some c -> | None -> } C w1 C C C C let! result = w2 c return result return None w2 C let compose w1 w2 ctx = async { let! result = w1 ctx match result with | Some c -> | None -> return None }
  213. compose C C w1 w2 let compose w1 w2 ctx

    = async { let! result = w1 ctx match result with | Some c -> | None -> } C w1 C C C C let! result = w2 c return result return None w2 C let compose w1 w2 ctx = async { let! result = w1 ctx match result with | Some c -> | None -> return None }
  214. compose C C w1 w2 let compose w1 w2 ctx

    = async { let! result = w1 ctx match result with | Some c -> | None -> } C w1 C C C C let! result = w2 c return result return None w2 C let compose w1 w2 ctx = async { let! result = w1 ctx match result with | Some c -> | None -> return None } return! w2 c
  215. Define compose Function WebPart -> WebPart -> Context -> Async<Context

    option> compose function takes two web parts and compose it together
  216. compose function is in turn composable! WebPart -> WebPart ->

    Context -> Async<Context option>
  217. compose function is in turn composable! WebPart -> WebPart ->

    Context -> Async<Context option> WebPart -> WebPart -> WebPart
  218. compose function is in turn composable! WebPart -> WebPart ->

    Context -> Async<Context option>
  219. compose function is in turn composable! WebPart -> WebPart ->

    Context -> Async<Context option> WebPart -> WebPart -> WebPart
  220. Introducing Operators >=> let (>=>) = compose

  221. Let’s Test

  222. Let’s Choose ! WebPart list -> Context -> Async<Context option>

    Choose function takes a list of web parts and returns the first one that matches the request λx
  223. Let’s Choose ! WebPart list -> Context -> Async<Context option>

    Choose function takes a list of web parts and returns the first one that matches the request λx let rec Choose webparts ctx = async { }
  224. Let’s Choose ! WebPart list -> Context -> Async<Context option>

    Choose function takes a list of web parts and returns the first one that matches the request λx let rec Choose webparts ctx = async { }
  225. Let’s Choose ! WebPart list -> Context -> Async<Context option>

    Choose function takes a list of web parts and returns the first one that matches the request λx let rec Choose webparts ctx = async { } match webparts with | [] -> return None | x :: xs ->
  226. Let’s Choose ! WebPart list -> Context -> Async<Context option>

    Choose function takes a list of web parts and returns the first one that matches the request λx let rec Choose webparts ctx = async { } match webparts with | [] -> return None | x :: xs ->
  227. Let’s Choose ! WebPart list -> Context -> Async<Context option>

    Choose function takes a list of web parts and returns the first one that matches the request λx let rec Choose webparts ctx = async { } match webparts with | [] -> return None | x :: xs -> let! result = x ctx
  228. Let’s Choose ! WebPart list -> Context -> Async<Context option>

    Choose function takes a list of web parts and returns the first one that matches the request λx let rec Choose webparts ctx = async { } match webparts with | [] -> return None | x :: xs -> let! result = x ctx
  229. Let’s Choose ! WebPart list -> Context -> Async<Context option>

    Choose function takes a list of web parts and returns the first one that matches the request λx let rec Choose webparts ctx = async { } match webparts with | [] -> return None | x :: xs -> let! result = x ctx match result with | Some c -> return Some c | None -> return! Choose xs ctx
  230. Let’s Choose ! WebPart list -> Context -> Async<Context option>

    Choose function takes a list of web parts and returns the first one that matches the request λx let rec Choose webparts ctx = async { } match webparts with | [] -> return None | x :: xs -> let! result = x ctx match result with | Some c -> return Some c | None -> return! Choose xs ctx
  231. Let’s Choose ! WebPart list -> Context -> Async<Context option>

    Choose function takes a list of web parts and returns the first one that matches the request λx let rec Choose webparts ctx = async { } match webparts with | [] -> return None | x :: xs -> let! result = x ctx match result with | Some c -> return Some c | None -> return! Choose xs ctx
  232. Let’s Choose ! WebPart list -> Context -> Async<Context option>

    Choose function takes a list of web parts and returns the first one that matches the request λx let rec Choose webparts ctx = async { } match webparts with | [] -> return None | x :: xs -> let! result = x ctx match result with | Some c -> return Some c | None -> return! Choose xs ctx
  233. Let’s Choose ! WebPart list -> Context -> Async<Context option>

    Choose function takes a list of web parts and returns the first one that matches the request λx let rec Choose webparts ctx = async { } match webparts with | [] -> return None | x :: xs -> let! result = x ctx match result with | Some c -> return Some c | None -> return! Choose xs ctx
  234. Let’s Play!

  235. https://fsharpforfunandprofit.com http://fsharp.org/ bit.ly/fsapplied https://fsharp.tv