objects |> functions


Cinco - Step 1

Let's take a look at the final framework we'll implement, Freya. As we've done the previous 4 times, ensure our project is Cinco.fsproj, and ensure the top PropertyGroup element looks like this.

1: 
2: 
3: 
4: 
5: 
6: 
7: 
<PropertyGroup>
  <AssemblyName>Cinco</AssemblyName>
  <VersionPrefix>2.0.0</VersionPrefix>
  <OutputType>Exe</OutputType>
  <TargetFramework>netcoreapp2.2</TargetFramework>
  <RootNamespace>Cinco</RootNamespace>
</PropertyGroup>

We'll also need to add Freya to paket.dependencies, then add a paket.references file with three entries:

1: 
2: 
3: 
Freya
Microsoft.AspNetCore.Owin
Microsoft.AspNetCore.Server.Kestrel

And, we'll rename Program.fs to App.fs and tell the compiler about it:

1: 
2: 
3: 
<ItemGroup>
  <Compile Include="App.fs" />
</ItemGroup>

Now, let's actually write App.fs:

1: 
2: 
3: 
4: 
5: 
6: 
namespace Cinco

open Freya.Core
open Freya.Machines.Http
open Microsoft.AspNetCore.Builder
open Microsoft.AspNetCore.Hosting

Freya.Core makes the OwinMidFunc module visible; Freya.Machines.Http provides the freyaMachine computation expression and the Represent module, which allows us to define our request-response.

1: 
2: 
3: 
4: 
5: 
module WebApp =
  let hello =
    freyaMachine {
      handleOk (Represent.text "Hello World from Freya")
      }

This code defines a machine which always returns our greeting in its OK response.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
[<RequireQualifiedAccess>]
module Configure =
  let app (app : IApplicationBuilder) =
    let freyaOwin = OwinMidFunc.ofFreya WebApp.hello
    app.UseOwin (fun p -> p.Invoke freyaOwin) |> ignore
  
module App =
  [<EntryPoint>]
  let main _ =
    use host =
      WebHostBuilder()
        .UseKestrel()
        .Configure(System.Action<IApplicationBuilder> Configure.app)
        .Build()
    host.Run()
    0

The Configure.app function is similar to other OWIN pipeline configurations we've used, although Freya provides the OwinMidFunc module to convert a Freya function into an OWIN function. The main function is identical to the one we used in Quatro.

You may be wondering why Freya is last, if we're going from less functional to more functional - especially with how terse Quatro ended up for this step. The answer is in the underlying implementation. Giraffe has a lot of defaults and convenience functions, including that text handler we used for our output; it then passes the results of these epxressions to ASP.NET Core for processing. Freya handles things completely differently; its HttpMachine starts out with nothing, and only requires processing for the code it handles. If you look at WebApp.hello, there is no logic in it to prevent an 200 OK response; no redirection, no authorization checks, no rate limits, etc. It does not pass that information off to ASP.NET Core; it simply returns that value because nothing has prevented it.

We will see machines that have more decisions than this one, and do more than just return text; when we do, you will see how each decision point is stated explicitly in that machine.

To see the results, dotnet run and open localhost:5000 to observe our Hello World message.


Back to Step 1

namespace Microsoft
namespace Freya
namespace Freya.Core
Multiple items
module Freya

from Freya.Core.Inference

--------------------
module Freya

from Freya.Core

--------------------
namespace Freya

--------------------
type Freya<'a> = State -> Async<FreyaResult<'a>>
namespace Freya.Machines
namespace Freya.Machines.Http
namespace Microsoft.AspNetCore
namespace Microsoft.AspNetCore.Builder
namespace Microsoft.AspNetCore.Hosting
val hello : HttpMachine
val freyaMachine : HttpMachineBuilder
custom operation: handleOk ('a)

Calls HttpMachineBuilder.HandleOk
module Represent

from Freya.Machines.Http
val text : text:string -> Representation
Multiple items
type RequireQualifiedAccessAttribute =
  inherit Attribute
  new : unit -> RequireQualifiedAccessAttribute

--------------------
new : unit -> RequireQualifiedAccessAttribute
val app : app:IApplicationBuilder -> unit
val app : IApplicationBuilder
type IApplicationBuilder =
  member ApplicationServices : IServiceProvider with get, set
  member Build : unit -> RequestDelegate
  member New : unit -> IApplicationBuilder
  member Properties : IDictionary<string, obj>
  member ServerFeatures : IFeatureCollection
  member Use : middleware:Func<RequestDelegate, RequestDelegate> -> IApplicationBuilder
val freyaOwin : OwinMidFunc
Multiple items
module OwinMidFunc

from Freya.Core

--------------------
type OwinMidFunc = System.Func<OwinAppFunc,OwinAppFunc>
val ofFreya : freya:'a -> OwinMidFunc (requires member Freya)
module WebApp

from Cinco
(extension) IApplicationBuilder.UseOwin() : System.Action<System.Func<System.Func<System.Collections.Generic.IDictionary<string,obj>,System.Threading.Tasks.Task>,System.Func<System.Collections.Generic.IDictionary<string,obj>,System.Threading.Tasks.Task>>>
(extension) IApplicationBuilder.UseOwin(pipeline: System.Action<System.Action<System.Func<System.Func<System.Collections.Generic.IDictionary<string,obj>,System.Threading.Tasks.Task>,System.Func<System.Collections.Generic.IDictionary<string,obj>,System.Threading.Tasks.Task>>>>) : IApplicationBuilder
val p : System.Action<System.Func<System.Func<System.Collections.Generic.IDictionary<string,obj>,System.Threading.Tasks.Task>,System.Func<System.Collections.Generic.IDictionary<string,obj>,System.Threading.Tasks.Task>>>
System.Action.Invoke(obj: System.Func<System.Func<System.Collections.Generic.IDictionary<string,obj>,System.Threading.Tasks.Task>,System.Func<System.Collections.Generic.IDictionary<string,obj>,System.Threading.Tasks.Task>>) : unit
val ignore : value:'T -> unit
module App

from Cinco
Multiple items
type EntryPointAttribute =
  inherit Attribute
  new : unit -> EntryPointAttribute

--------------------
new : unit -> EntryPointAttribute
val main : string [] -> int
val host : IWebHost
Multiple items
type WebHostBuilder =
  new : unit -> WebHostBuilder
  member Build : unit -> IWebHost
  member ConfigureAppConfiguration : configureDelegate:Action<WebHostBuilderContext, IConfigurationBuilder> -> IWebHostBuilder
  member ConfigureServices : configureServices:Action<IServiceCollection> -> IWebHostBuilder + 1 overload
  member GetSetting : key:string -> string
  member UseSetting : key:string * value:string -> IWebHostBuilder

--------------------
WebHostBuilder() : WebHostBuilder
module Configure

from Cinco
namespace System
Multiple items
type Action<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10,'T11,'T12,'T13,'T14,'T15,'T16> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 * 'T14 * 'T15 * 'T16 -> unit

--------------------
type Action<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10,'T11,'T12,'T13,'T14,'T15> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 * 'T14 * 'T15 -> unit

--------------------
type Action<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10,'T11,'T12,'T13,'T14> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 * 'T14 -> unit

--------------------
type Action<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10,'T11,'T12,'T13> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 * 'T13 -> unit

--------------------
type Action<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10,'T11,'T12> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 * 'T12 -> unit

--------------------
type Action<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10,'T11> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 * 'T11 -> unit

--------------------
type Action<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9,'T10> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 * 'T10 -> unit

--------------------
type Action<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8,'T9> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 * 'T9 -> unit

--------------------
type Action<'T1,'T2,'T3,'T4,'T5,'T6,'T7,'T8> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 * 'T8 -> unit

--------------------
type Action<'T1,'T2,'T3,'T4,'T5,'T6,'T7> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 * 'T7 -> unit

--------------------
type Action<'T1,'T2,'T3,'T4,'T5,'T6> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 * 'T6 -> unit

--------------------
type Action<'T1,'T2,'T3,'T4,'T5> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 * 'T5 -> unit

--------------------
type Action<'T1,'T2,'T3,'T4> =
  delegate of 'T1 * 'T2 * 'T3 * 'T4 -> unit

--------------------
type Action<'T1,'T2,'T3> =
  delegate of 'T1 * 'T2 * 'T3 -> unit

--------------------
type Action<'T1,'T2> =
  delegate of 'T1 * 'T2 -> unit

--------------------
type Action =
  delegate of unit -> unit

--------------------
type Action<'T> =
  delegate of 'T -> unit
(extension) IWebHost.Run() : unit
Fork me on GitHub