Let's Create MiniSuave

Let's Create MiniSuave

Suave is a simple web development F# library providing a lightweight web server and a set of combinators to manipulate route flow and task composition. The better way for you to learn about Suave is for you to build Suave. In this interactive, hands-on tutorial, you will discover the development of a minimal version of the Suave library.

You will learn:

Functional-First Programming with F#

Suave library from the ground up

Implementing bigger things by combining smaller functions

How to learn by synthesis, a powerful learning technique

C6dbbb399f7658917f60bd1e2a2663ed?s=128

Tamizhvendan S

December 05, 2016
Tweet

Transcript

  1. Let’s build MiniSuave λ

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

    bit.ly/fsapplied
  3. Tutorial Outline

  4. Tutorial Outline λ It’s Beginner friendly!

  5. Tutorial Outline λ It’s Beginner friendly! λ Functional Programming in

    three steps
  6. Tutorial Outline λ It’s Beginner friendly! λ Functional Programming in

    three steps λ Building a minimal web development library
  7. Mr. AcuBot My name is Bot! AcuBot!

  8. Functional Programming My Story

  9. Functional Programming x Model your Domain (Data)

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

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

    composing functions
  12. Let’s Apply

  13. Learn By Synthesis

  14. Learn By Synthesis http://bit.ly/29QAUyp

  15. Learn By Synthesis http://bit.ly/29QAUyp http://www.keyword-suggestions.com/

  16. Learn By Synthesis http://bit.ly/29QAUyp http://www.keyword-suggestions.com/

  17. Learn By Synthesis Don’t dissect the frog, build it! http://bit.ly/29QAUyp

    http://www.keyword-suggestions.com/
  18. Domain

  19. Domain User sends a Request and gets a Response after

    some time
  20. Domain User sends a Request and gets a Response after

    some time Request contains HttpMethod, Headers & a Resource Path
  21. 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
  22. 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
  23. 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
  24. Domain

  25. Domain Response contains StatusCode, Headers & Content

  26. Domain Response contains StatusCode, Headers & Content StatusCode will be

    any one of Ok, NotFound, BadRequest
  27. Domain Response contains StatusCode, Headers & Content StatusCode will be

    any one of Ok, NotFound, BadRequest Headers is a list of Key Value pairs
  28. 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.
  29. Let’s Build! MiniSuave A simple web development F# library https://github.com/tamizhvendan/acubot

  30. Bootstrapping Mr.AcuBot https://github.com/tamizhvendan/acubot ./build.sh (OS X or Linux) ./build.cmd (Windows)

  31. Pairing With Mr.AcuBot

  32. Functional Programming x Model your Domain (Data)

  33. Challenge 1 Model HttpMethod HttpMethod will be one of the

    following Get, Put, Post, Delete type Color = | Red | Green | Blue x
  34. type HttpMethod = | Get | Put | Delete |

    Post
  35. Challenge 2 Model Header Header is a name value pair

    type Point = int * int x
  36. type Header = string * string

  37. Challenge 3 Model Request Request contains HttpMethod, Path, Headers type

    Shape = { Color : Color Points : Point list Label : string } x
  38. type Request = { Path : string Headers : Header

    list HttpMethod : HttpMethod }
  39. Challenge 4 Model StatusCode StatusCode will be one of the

    following Ok, NotFound, BadRequest type Color = | Red | Green | Blue x
  40. type StatusCode = | Ok | BadRequest | NotFound

  41. Challenge 5 Model Response Response contains StatusCode, Headers & Content

    type Circle = { Color : Color Radius : double } x
  42. type Response = { Content : string Headers : Header

    list StatusCode : StatusCode }
  43. Designing Request Handlers

  44. Designing Request Handlers express.js Go Spark Java

  45. Designing Request Handlers ASP.NET Web API Message Handler express.js Go

    Spark Java
  46. Designing Request Handlers ASP.NET Web API Message Handler express.js Go

    Spark Java
  47. Designing Request Handlers ASP.NET Web API Message Handler express.js Go

    Spark Java
  48. Design For Composition

  49. Design For Composition a f1 b

  50. Design For Composition a f1 b b f2 c

  51. Design For Composition a f1 b b f2 c >>

  52. Design For Composition a f1 b b f2 c >>

    a f1 >> f2 c
  53. Design For Composition a f1 b b f2 c >>

    a f1 >> f2 c req handler1 res
  54. Design For Composition a f1 b b f2 c >>

    a f1 >> f2 c req handler1 res req handler2 res
  55. Design For Composition a f1 b b f2 c >>

    a f1 >> f2 c req handler1 res req handler2 res
  56. Design For Composition a f1 b b f2 c >>

    a f1 >> f2 c req handler1 res req handler2 res
  57. Design For Composition a f1 b b f2 c >>

    a f1 >> f2 c req handler1 res req handler2 res >>
  58. Design For Composition a f1 b b f2 c >>

    a f1 >> f2 c req handler1 res req handler2 res >>
  59. Design For Composition a f1 b b f2 c >>

    a f1 >> f2 c req handler1 res req handler2 res >>
  60. Design For Composition a f1 b b f2 c >>

    a f1 >> f2 c req handler1 res req handler2 res >> x
  61. Design For Composition a f1 b b f2 c >>

    a f1 >> f2 c req handler1 res req handler2 res >> x Create a new type containing Request & Response
  62. Challenge 6 Model Context Context contains Request & Response type

    Shape = { Rectangle : Rectangle Circle : Circle } x
  63. type Context = { Request : Request Response : Response

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

  65. C handler1 C C handler2 C If handler1 handle the

    request don’t invoke handler2 Design For Composition
  66. C handler1 C C handler2 C If handler1 handle the

    request don’t invoke handler2 Invoke handler2 always Design For Composition
  67. Design For Composition

  68. C handler1 Design For Composition

  69. C handler1 Design For Composition

  70. C handler1 Design For Composition C handler2

  71. C handler1 Design For Composition C handler2 C

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

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

    C
  74. Web is Async

  75. Web is Async POST /message Chat Server CREATE

  76. Web is Async POST /message Chat Server CREATE

  77. Web is Async POST /message Chat Server CREATE OK Chat

    Server Inserted
  78. Design For Composition Async Type Option Type

  79. C handler1 Design For Composition Async Type Option Type

  80. C handler1 Design For Composition Async Type Option Type

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

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

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

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

    C Async Type Option Type
  85. Challenge 7 Model WebPart In Suave, a handler is termed

    as WebPart WebPart takes a context and asynchronously may return the (modified) context. type Draw = Shape -> Async<Shape option> A type can represent a function signature x
  86. type WebPart = Context -> Async<Context option>

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

    (Data)
  88. Modifying Record Types in F# Use practise.fsx

  89. Modifying Record Types in F# Use practise.fsx // Defining a

    Record type type Person = { Id : int Name : string Age : int }
  90. Modifying Record Types in F# Use practise.fsx // Defining a

    Record type type Person = { Id : int Name : string Age : int } // create a value of Record type of Person let john = { Id = 1 Name = "John" Age = 28 }
  91. Modifying Record Types in F# // Changing John's Age and

    Id // Records are immutable let updatedJohn = {john with Age = 29 Id = 2} Use practise.fsx // Defining a Record type type Person = { Id : int Name : string Age : int } // create a value of Record type of Person let john = { Id = 1 Name = "John" Age = 28 }
  92. Functions in F# Use practise.fsx

  93. Functions in F# Use practise.fsx // Parameters are separated by

    spaces let isAdult person = // last expression's result is the return value person.Age > 18
  94. Functions in F# Use practise.fsx // Parameters are separated by

    spaces let isAdult person = // last expression's result is the return value person.Age > 18 type DbConn = unit
  95. Functions in F# Use practise.fsx // Parameters are separated by

    spaces let isAdult person = // last expression's result is the return value person.Age > 18 type DbConn = unit // DbConn -> int -> Person let getPersonFromDbById dbConn id = printfn "fetching person : %d" id john
  96. Functions in F# Use practise.fsx // Parameters are separated by

    spaces let isAdult person = // last expression's result is the return value person.Age > 18 type DbConn = unit let dbConn = () // Initialising Db Conn // DbConn -> int -> Person let getPersonFromDbById dbConn id = printfn "fetching person : %d" id john
  97. Functions in F# // Functions can be partially applied //

    int -> Person let getPersonById = getPersonFromDbById dbConn Use practise.fsx // Parameters are separated by spaces let isAdult person = // last expression's result is the return value person.Age > 18 type DbConn = unit let dbConn = () // Initialising Db Conn // DbConn -> int -> Person let getPersonFromDbById dbConn id = printfn "fetching person : %d" id john
  98. Option Type & Async in F# Use practise.fsx

  99. Option Type & Async in F# Use practise.fsx // string

    option let email = Some "foo@bar.com"
  100. Option Type & Async in F# Use practise.fsx // string

    option let email = Some "foo@bar.com" // 'a option let emailNotProvided = None
  101. Option Type & Async in F# // Async<string option> let

    asyncEmail = async.Return (Some "foo@bar.com") let asyncEmail2 = "foo@bar.com" |> Some |> async.Return Use practise.fsx // string option let email = Some "foo@bar.com" // 'a option let emailNotProvided = None
  102. Option Type & Async in F# Use practise.fsx

  103. Option Type & Async in F# Use practise.fsx // DbConn

    -> int -> Async<Person option> let tryGetPersonFromDbById dbConn id = // Db access logic match id = 2 with | true -> john |> Some |> async.Return | false -> None |> async.Return
  104. Option Type & Async in F# Use practise.fsx // int

    -> Async<Person option> let tryGetPersonById = tryGetPersonFromDbById dbConn // DbConn -> int -> Async<Person option> let tryGetPersonFromDbById dbConn id = // Db access logic match id = 2 with | true -> john |> Some |> async.Return | false -> None |> async.Return
  105. Combinator Pattern

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

  107. Combinator Pattern

  108. Combinator Pattern combinator<‘a> : ‘a -> WebPart

  109. Combinator Pattern combinator<‘a> : ‘a -> WebPart Lego Block Creator

    Red
  110. Combinator Pattern combinator<‘a> : ‘a -> WebPart Lego Block Creator

    Green Lego Block Creator Red
  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. Combinator type WebPart = Context -> Async<Context option> λx

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

    create WebPart λx
  117. Challenge 8 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 λx Define OK Combinator
  118. Challenge 8 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> λx Define OK Combinator
  119. Challenge 8 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> λx C WebPart C Define OK Combinator
  120. let OK content ctx = let response = {ctx.Response with

    StatusCode = Ok Content = content} {ctx with Response = response} |> Some |> async.Return
  121. Let’s Test run (OK "test");; run <| OK "test";; ./test.sh

    ./test.cmd Use #q;; to Exit
  122. Challenge 9 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> λx
  123. let NOT_FOUND content ctx = let response = {ctx.Response with

    StatusCode = NotFound Content = content} {ctx with Response = response} |> Some |> async.Return
  124. Challenge 10 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> λx
  125. let BAD_REQUEST content ctx = let response = {ctx.Response with

    StatusCode = BadRequest Content = content} {ctx with Response = response} |> Some |> async.Return
  126. Rule of Three

  127. Challenge 11 Let’s Refactor let response statusCode content ctx =

    let response = {ctx.Response with StatusCode = statusCode Content = content} {ctx with Response = response} |> Some |> async.Return λx
  128. Challenge 11 Let’s Refactor let response statusCode content ctx =

    let response = {ctx.Response with StatusCode = statusCode Content = content} {ctx with Response = response} |> Some |> async.Return let OK = response Ok let BAD_REQUEST = response BadRequest let NOT_FOUND = response NotFound λx
  129. Let’s Test run (BAD_REQUEST "test");; run (NOT_FOUND "test");; Use #q;;

    to Exit ./test.sh ./test.cmd
  130. C WebPart C

  131. Filters

  132. C WebPart Filters

  133. C WebPart Filters

  134. C WebPart C WebPart Filters

  135. C WebPart C WebPart C Filters

  136. Challenge 12 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> λx let GREEN_CIRCLE circle = match circle.Color with | Green -> circle |> Some |> async.Retun | _ -> None |> async.Return
  137. let GET ctx = match ctx.Request.HttpMethod with | Get ->

    Some ctx |> async.Return | _ -> None |> async.Return
  138. Challenge 13 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> λx
  139. let POST ctx = match ctx.Request.HttpMethod with | Post ->

    Some ctx |> async.Return | _ -> None |> async.Return
  140. Challenge 14 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> λx
  141. let PUT ctx = match ctx.Request.HttpMethod with | Put ->

    Some ctx |> async.Return | _ -> None |> async.Return
  142. Challenge 15 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> λx
  143. let DELETE ctx = match ctx.Request.HttpMethod with | Delete ->

    Some ctx |> async.Return | _ -> None |> async.Return
  144. Challenge 16 Its time for Refactoring All Http Method filter

    handlers looks for a particular HttpMethod let httpMethodFilter httpMethod ctx = match ctx.Request.HttpMethod = httpMethod with | true -> Some ctx |> async.Return | _ -> None |> async.Return λx
  145. Challenge 16 Its time for Refactoring All Http Method filter

    handlers looks for a particular HttpMethod let httpMethodFilter httpMethod ctx = match ctx.Request.HttpMethod = httpMethod with | true -> Some ctx |> async.Return | _ -> None |> async.Return let GET = httpMethodFilter Get let POST = httpMethodFilter Post let PUT = httpMethodFilter Put let DELETE = httpMethodFilter Delete λx
  146. Let’s Test execute “Get;/” GET;; execute “Get;/” POST;; execute “Post;/”

    POST;; Use #q;; to Exit ./test.sh ./test.cmd
  147. Challenge 17 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 λx
  148. let Path path ctx = match ctx.Request.Path = path with

    | true -> ctx |> Some |> async.Return | _ -> None |> async.Return
  149. Let’s Test execute "Get;/hello" (Path "/hello");; execute "Get;/hi" (Path "/hello");;

    ./test.sh ./test.cmd
  150. Functional Programming >> >=> >>= << |> Define “System” by

    composing functions
  151. Function Composition

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

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

    f1 >> f2 z x f1 y y f2 z >>x f1 >> f2 >> f3 a z f3 a
  154. Combinator Pattern type WebPart = Context -> Async<Context option>

  155. Combinator Pattern type WebPart = Context -> Async<Context option> functions

    that compose WebParts
  156. Function Composition

  157. Function Composition

  158. Function Composition None

  159. Function Composition C None

  160. Function Composition C Some<C> None

  161. Function Composition C Some<C> None

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

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

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

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

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

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

    Context -> Async<Context option> C C WebPart C C WebPart
  168. 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
  169. 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
  170. 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
  171. 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
  172. 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
  173. 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
  174. 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
  175. 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
  176. 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
  177. 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
  178. 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
  179. 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
  180. 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
  181. 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
  182. 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 Use practise.fsx
  183. 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
  184. Option in F# Use practise.fsx // 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
  185. Option in F# Use practise.fsx // 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
  186. Option in F# Use practise.fsx // 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
  187. Option in F# Use practise.fsx // 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
  188. Option in F# Use practise.fsx // 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
  189. Option in F# Use practise.fsx // 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
  190. Option in F# Use practise.fsx // 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
  191. Option in F# Use practise.fsx // 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
  192. Option in F# Use practise.fsx // 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
  193. Option in F# Use practise.fsx // 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
  194. Composing WebParts

  195. >=> C w1 C C w2 C C w1 Composing

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

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

    WebPart = Context -> Async<Context option> Composing WebParts
  198. >=> 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>
  199. >=> 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
  200. >=> 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
  201. >=> 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
  202. compose C C w1 w2

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

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

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

  206. compose C C w1 w2 let compose w1 w2 ctx

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

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

    = async { return Some ctx } let! result = w1 ctx Let’s go inside compose
  209. 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
  210. 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
  211. 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
  212. compose C C w1 w2 C w1 C C

  213. compose C C w1 w2 let compose w1 w2 ctx

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

    = async { let! result = w1 ctx return Some ctx } C w1 C C
  215. 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 -> ()
  216. 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
  217. compose C C w1 w2 C w1 C C C

    C
  218. 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
  219. 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
  220. 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
  221. 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
  222. 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 }
  223. 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 }
  224. 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
  225. Challenge 18 Define compose Function WebPart -> WebPart -> Context

    -> Async<Context option> compose function takes two web parts and compose it together let compose w1 w2 ctx = async { let! result = w1 ctx match result with | Some c -> return! w2 c | None -> return None } λx
  226. compose function is in turn composable! WebPart -> WebPart ->

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

    Context -> Async<Context option> WebPart -> WebPart -> WebPart
  228. Challenge 19 Introducing Operators >=> let (>=>) = compose λx

  229. Let’s Test ./test.sh ./test.cmd

  230. Recursive Functions in F# Use practise.fsx let rec firstEven nums

    = match nums with | [] -> None | x :: xs -> match x % 2 = 0 with | true -> Some x | _ -> firstEven xs firstEven [1;5;2;4;8]
  231. Recursive Functions in F# Use practise.fsx let rec firstEven nums

    = match nums with | [] -> None | x :: xs -> match x % 2 = 0 with | true -> Some x | _ -> firstEven xs firstEven [1;5;2;4;8]
  232. Recursive Functions in F# Use practise.fsx let rec firstEven nums

    = match nums with | [] -> None | x :: xs -> match x % 2 = 0 with | true -> Some x | _ -> firstEven xs firstEven [1;5;2;4;8]
  233. Recursive Functions in F# Use practise.fsx let rec firstEven nums

    = match nums with | [] -> None | x :: xs -> match x % 2 = 0 with | true -> Some x | _ -> firstEven xs firstEven [1;5;2;4;8]
  234. Recursive Functions in F# Use practise.fsx let rec firstEven nums

    = match nums with | [] -> None | x :: xs -> match x % 2 = 0 with | true -> Some x | _ -> firstEven xs firstEven [1;5;2;4;8]
  235. Recursive Functions in F# Use practise.fsx let rec firstEven nums

    = match nums with | [] -> None | x :: xs -> match x % 2 = 0 with | true -> Some x | _ -> firstEven xs firstEven [1;5;2;4;8]
  236. Recursive Functions in F# Use practise.fsx let rec firstEven nums

    = match nums with | [] -> None | x :: xs -> match x % 2 = 0 with | true -> Some x | _ -> firstEven xs firstEven [1;5;2;4;8]
  237. Recursive Functions in F# Use practise.fsx let rec firstEven nums

    = match nums with | [] -> None | x :: xs -> match x % 2 = 0 with | true -> Some x | _ -> firstEven xs firstEven [1;5;2;4;8]
  238. Recursive Functions in F# Use practise.fsx let rec firstEven nums

    = match nums with | [] -> None | x :: xs -> match x % 2 = 0 with | true -> Some x | _ -> firstEven xs firstEven [1;5;2;4;8]
  239. Recursive Functions in F# Use practise.fsx let rec firstEven nums

    = match nums with | [] -> None | x :: xs -> match x % 2 = 0 with | true -> Some x | _ -> firstEven xs firstEven [1;5;2;4;8]
  240. Recursive Functions in F# Use practise.fsx let rec firstEven nums

    = match nums with | [] -> None | x :: xs -> match x % 2 = 0 with | true -> Some x | _ -> firstEven xs firstEven [1;5;2;4;8]
  241. Challenge 20 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
  242. Challenge 20 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 { }
  243. Challenge 20 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 { }
  244. Challenge 20 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 ->
  245. Challenge 20 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 ->
  246. Challenge 20 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
  247. Challenge 20 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
  248. Challenge 20 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
  249. Challenge 20 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
  250. Challenge 20 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
  251. Challenge 20 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
  252. Challenge 20 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
  253. The Real Play! play.sh play.cmd let app = Choose[ GET

    >=> Choose [ Path "/hello" >=> OK "hello" Path "/hi" >=> OK "hi" ] POST >=> Path "/hello" >=> OK "hello POST" ]
  254. Summary Model your Domain (Data) Define functions which operate on

    your Domain (Data) Define “System” by composing functions
  255. https://fsharpforfunandprofit.com http://suave.io bit.ly/fsapplied