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

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

Tamizhvendan S

December 05, 2016
Tweet

More Decks by Tamizhvendan S

Other Decks in Programming

Transcript

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

    three steps λ Building a minimal web development library
  2. Domain User sends a Request and gets a Response after

    some time Request contains HttpMethod, Headers & a Resource Path
  3. 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
  4. 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
  5. 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
  6. Domain Response contains StatusCode, Headers & Content StatusCode will be

    any one of Ok, NotFound, BadRequest Headers is a list of Key Value pairs
  7. 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.
  8. Challenge 1 Model HttpMethod HttpMethod will be one of the

    following Get, Put, Post, Delete type Color = | Red | Green | Blue x
  9. Challenge 3 Model Request Request contains HttpMethod, Path, Headers type

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

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

    following Ok, NotFound, BadRequest type Color = | Red | Green | Blue x
  12. Challenge 5 Model Response Response contains StatusCode, Headers & Content

    type Circle = { Color : Color Radius : double } x
  13. Design For Composition a f1 b b f2 c >>

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

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

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

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

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

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

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

    a f1 >> f2 c req handler1 res req handler2 res >> x
  21. 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
  22. Challenge 6 Model Context Context contains Request & Response type

    Shape = { Rectangle : Rectangle Circle : Circle } x
  23. C handler1 C C handler2 C If handler1 handle the

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

    request don’t invoke handler2 Invoke handler2 always Design For Composition
  25. 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
  26. Modifying Record Types in F# Use practise.fsx // Defining a

    Record type type Person = { Id : int Name : string Age : int }
  27. 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 }
  28. 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 }
  29. 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
  30. 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
  31. 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
  32. 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
  33. 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
  34. Option Type & Async in F# Use practise.fsx // string

    option let email = Some "[email protected]" // 'a option let emailNotProvided = None
  35. Option Type & Async in F# // Async<string option> let

    asyncEmail = async.Return (Some "[email protected]") let asyncEmail2 = "[email protected]" |> Some |> async.Return Use practise.fsx // string option let email = Some "[email protected]" // 'a option let emailNotProvided = None
  36. 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
  37. 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
  38. Combinator Pattern type WebPart = Context -> Async<Context option> The

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

    that create WebPart The application is a list of WebParts Combined together in some order
  40. 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
  41. 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
  42. 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
  43. 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
  44. let OK content ctx = let response = {ctx.Response with

    StatusCode = Ok Content = content} {ctx with Response = response} |> Some |> async.Return
  45. 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
  46. let NOT_FOUND content ctx = let response = {ctx.Response with

    StatusCode = NotFound Content = content} {ctx with Response = response} |> Some |> async.Return
  47. 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
  48. let BAD_REQUEST content ctx = let response = {ctx.Response with

    StatusCode = BadRequest Content = content} {ctx with Response = response} |> Some |> async.Return
  49. 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
  50. 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
  51. 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
  52. let GET ctx = match ctx.Request.HttpMethod with | Get ->

    Some ctx |> async.Return | _ -> None |> async.Return
  53. 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
  54. let POST ctx = match ctx.Request.HttpMethod with | Post ->

    Some ctx |> async.Return | _ -> None |> async.Return
  55. 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
  56. let PUT ctx = match ctx.Request.HttpMethod with | Put ->

    Some ctx |> async.Return | _ -> None |> async.Return
  57. 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
  58. let DELETE ctx = match ctx.Request.HttpMethod with | Delete ->

    Some ctx |> async.Return | _ -> None |> async.Return
  59. 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
  60. 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
  61. 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
  62. let Path path ctx = match ctx.Request.Path = path with

    | true -> ctx |> Some |> async.Return | _ -> None |> async.Return
  63. 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
  64. Function Composition Async<None> Async<Some<C>> C Some<C> None type WebPart =

    Context -> Async<Context option> C C WebPart C C WebPart
  65. 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
  66. 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
  67. 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
  68. 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
  69. 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
  70. 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
  71. 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
  72. 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
  73. 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
  74. 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
  75. 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
  76. 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
  77. 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
  78. 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
  79. 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
  80. 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
  81. 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
  82. 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
  83. 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
  84. 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
  85. 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
  86. 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
  87. 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
  88. 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
  89. 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
  90. 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
  91. >=> C w1 C C w2 C C w1 type

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

    WebPart = Context -> Async<Context option> Composing WebParts
  93. >=> 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>
  94. >=> 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
  95. >=> 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
  96. >=> 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
  97. compose C C w1 w2 let compose w1 w2 ctx

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

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

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

    = async { return Some ctx } let! result = w1 ctx Let’s go inside compose
  101. 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
  102. 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
  103. 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
  104. compose C C w1 w2 let compose w1 w2 ctx

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

    = async { let! result = w1 ctx return Some ctx } C w1 C C
  106. 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 -> ()
  107. 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
  108. 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
  109. 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
  110. 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
  111. 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
  112. 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 }
  113. 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 }
  114. 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
  115. 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
  116. compose function is in turn composable! WebPart -> WebPart ->

    Context -> Async<Context option> WebPart -> WebPart -> WebPart
  117. 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]
  118. 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]
  119. 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]
  120. 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]
  121. 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]
  122. 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]
  123. 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]
  124. 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]
  125. 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]
  126. 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]
  127. 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]
  128. 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
  129. 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 { }
  130. 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 { }
  131. 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 ->
  132. 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 ->
  133. 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
  134. 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
  135. 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
  136. 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
  137. 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
  138. 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
  139. 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
  140. 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" ]
  141. Summary Model your Domain (Data) Define functions which operate on

    your Domain (Data) Define “System” by composing functions