I've started learning F# and Suave
and I'm reading the book F# Applied.
One thing I'm struggling with is the warbler
function. I know its something to do with deferring execution but I don't really understand why and when its needed.
Apparently we could also use the request
function as an alternative to warbler
.
Can anyone provide any more detail on why and when these functions are used.
The other answer already explained the warbler
function and its relation to context
and request
functions. I'd like to show when do you want to use these.
When you start a Suave server, you need to provide it with the request processing pipeline of WebParts
- routing, HTTP methods and the response-generating functions. This means that by the time you start the web server all the parameters provided to the partially applied WebPart
functions have already been evaluated.
Imagine a minimalistic web app that prints the current server time:
let app = GET >=> path "/" >=> OK (string DateTime.Now)
If you start a web server using this app
pipeline, you'll always see the same timestamp generated when the app
value was created, no matter when you make the web requests retrieving it.
The warbler
function and its specialized versions context
and request
not only defer the execution, but also enable the web server to call the provided function every time it needs its result.
In the example scenario this app
will provide expected results:
let app = GET >=> path "/" >=> warbler (fun ctx -> OK (string DateTime.Now))
@adzdavies' comment shows an alternative approach where you don't necessarily need warbler
. In the example you can also defer the parameter evaluation if you use anonymous function syntax instead of partially applying OK
.
let app = GET >=> path "/" >=> (fun ctx -> OK (string DateTime.Now) ctx)
These three functions are related in the sense that request
and context
are specialized versions of warbler
. They all do the same thing - they inspect (some aspect of) their argument and give you back a function to apply to that argument.
Remember that the basic "building block" of Suave, WebPart
, is a function HttpContext -> Async<HttpContext option>
rather than some concrete object. What this effectively means is that those three functions allow you to inspect this HttpContext
and based on that compose a WebPart
to use.
At its core, what warbler
does is very simple:
let warbler f a = f a a
// ('t -> 't -> 'u) -> 't -> 'u
You give it a function f
and argument a
. Function f
looks at a
and gives you back a new function 't -> 'u
which is then applied to a
.
The thing about warbler
is that it's entirely generic - you can use it anywhere you'd use context
or request
as long as the types align, but it doesn't know anything about the domain Suave is interested in.
That's why there are the specialized versions of it that "speak the domain language":
let request apply (a : HttpContext) = apply a.request a
// (HttpRequest -> HttpContext -> 'a) -> HttpContext -> 'a
let context apply (a : HttpContext) = apply a a
// (HttpContext -> HttpContext -> 'a) -> HttpContext -> 'a
Notice that they have the same "shape" as warbler - the only difference being that the HttpContext
type is "hardcoded" - making it more convenient to use.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With