You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I have found that my complex Suave code can be quite deeply nested. To fix this, I've been sketching out some abstractions that might help to make code more linear. Here's what I came up with.
A WebFlow is like a WebPart, except that it carries a strongly-typed value:
A WebPart is logically equivalent to a WebFlow<unit>.
Basic functions for working with WebFlow values:
[<RequireQualifiedAccess>]moduleWebFlow =letofAsync(wf :Async<'t>):WebFlow<'t>=fun ctx ->async{let!t= wf
return Some (t, ctx)}letofWebPart(part :WebPart):WebFlow<unit>=fun ctx ->async{let!m= part ctx
return
m
|> Option.map (fun ctx ->(), ctx)}lettoWebPart(flow :WebFlow<unit>):WebPart =fun ctx ->async{let!m= flow ctx
return
m
|> Option.map snd
}letctx:WebFlow<HttpContext>=fun ctx ->async{return Some (ctx, ctx)}letjust x :WebFlow<'t>=fun ctx ->async{return Some (x, ctx)}letzero<'t>:WebFlow<'t>=fun _ ->async{return None
}letmap(f :'t ->'u)(flow :WebFlow<'t>):WebFlow<'u>=fun ctx ->async{let!m= flow ctx
return
m
|> Option.map (fun(t,ctx)-> f t, ctx)}letbind(f :'t ->WebFlow<'u>)(flow :WebFlow<'t>):WebFlow<'u>=fun ctx ->async{let!m= flow ctx
match m with| Some (t, ctx)->letnext= f t
return! next ctx
| None ->return None
}
And from these we can make a computation expression:
[<AutoOpen>]moduleWebFlowSyntax =typeWebFlowBuilder()=memberthis.Bind(m,f)=
WebFlow.bind f m
memberthis.Return(x)=
WebFlow.just x
memberthis.ReturnFrom(x)=(x : WebFlow<'t>)memberthis.BindReturn(m,f)=
WebFlow.map f m
memberthis.Zero()=
WebFlow.zero
[<AutoOpen>]moduleAsyncExtensions =typeWebFlowBuilderwithmemberthis.Bind(m,f)=
WebFlow.bind f (WebFlow.ofAsync m)memberthis.BindReturn(m,f)=
WebFlow.map f (WebFlow.ofAsync m)[<AutoOpen>]moduleWebPartExtensions =typeWebFlowBuilderwithmemberthis.Bind(m,f)=
WebFlow.bind f (WebFlow.ofWebPart m)memberthis.BindReturn(m,f)=
WebFlow.map f (WebFlow.ofWebPart m)letwebFlow= WebFlowBuilder()
With this setup, apps can be very terse yet readable!
I have found that my complex Suave code can be quite deeply nested. To fix this, I've been sketching out some abstractions that might help to make code more linear. Here's what I came up with.
A
WebFlow
is like aWebPart
, except that it carries a strongly-typed value:A
WebPart
is logically equivalent to aWebFlow<unit>
.Basic functions for working with
WebFlow
values:And from these we can make a computation expression:
With this setup, apps can be very terse yet readable!
Before:
After:
(Implementation of
Filters.pathScanCiFlow
andAuthentication.tryBasicFlow
omitted, but they are quite simple)I'm curious what people think!
The text was updated successfully, but these errors were encountered: