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.
I found the prior explanation confusing (to me). This is my attempt at clarity...
warbler resolves a problem with optimized impure eager evaluated functional languages in which partially applied arguments are evaluated early and cached. This caching presents a problem when those applied arguments are dependent on side effects and it becomes desirable to have fresh values with each invocation. For example, the following query for the string representation of the current system's time will occur and be cached at the definition of g: string -> string. As such, it will return the same value for each subsequent call to g:
let g = sprintf "%s %s" (string DateTime.Now)
g "a" //"12/09/2020 18:33:32 a"
g "b" //"12/09/2020 18:33:32 b"
However, the warbler concept is unnecessary to resolve this reevaluation issue. It is enough to simply wrap the subject function inside an anonymous function that then fully applies the subject function each time, as follows:
let f = (fun x -> sprintf "%s %s" (string DateTime.Now) x)
f "c" //"12/09/2020 18:53:32 c"
f "d" //"12/09/2020 18:53:34 d"
What warbler is doing instead is using the above anonymous function as a function factory that produces the subject function when invoked. Then invoking that subject function with its second argument. It is incidental that warbler uses its second argument to invoke the factory function but it does present a point of misdirection. Conceivably, passing the argument to the factory can allow the factory to configure the subject function function or select alternative type compatible functions to return to the warbler. Still, that is not what the warbler is intended for.
let warbler f x = (f x) x
It should be noted that for reevaluation to work, f, must be an anonymous function at the point of call. Consequently, there seems to be no longer any utility for the warbler concept and the cool name should probably be deprecated and allowed to resurface for some other useful concept.
Incidentally, my encounter with warbler is with Giraffe.
Related
I'm trying to learn the SAFE Stack at the moment, specifically attempting to handle URL navigation via Elmish; I've followed the example code on the Elmish site that defines a route mapping function and then passes that to the parsePath function.
However, Program.toNavigable expects a Parser<'a> type (a type alias for Location -> 'a) as its first argument, but the sample code (parsePath routes) first argument is a Location -> 'a option.
Obviously i can use function composition to get the correct typing, but it seems like I'm missing something here. Can anyone familiar with URL navigation in Elmish advise?
Well, a Parser<'a option> is a Parser<'a> (just with another 'a), so things should compose just fine.
Say, e.g., that the following type defines all navigation:
type Route = Blog of int | Search of string
Then the parties involved should have the following types:
init: Route option -> Model * Cmd<Msg>
parser: Parser<Route option>
urlUpdate: Route option -> Model -> Model * Cmd<Msg>
and you compose your program thusly:
Program.mkProgram init update view
|> Program.toNavigable parser urlUpdate
|> Program.withReactBatched "elmish-app"
|> Program.run
what's the correct way to pass a value to the second paramater of a function in a pipeline?
e.g.
async {
let! response =
someData
|> JsonConvert.SerializeObject
|> fun x -> new StringContent(x)
|> httpClient.PostAsync "/DoSomething"
|> Async.AwaitTask
}
in the above code PostAsync takes 2 parameters, the url to post to and the content you want to post. Have tried the back pipe too, and parenthesis, but cant quite figure out how to do it
any ideas?
PostAsync has non-curried parameters, which cannot be passed in one by one, they have to be passed all at once. This is why you should always have your parameters curried.
But alas, you can't control the definition of PostAsync, because it's a .NET library method, so you have to wrap it one way or another. There are a few options:
Option 1: use a lambda expression:
|> fun body -> httpClient.PostAsync( "/DoSomething", body )
Option 2: declare yourself a function with curried parameters
let postAsync client url body =
client.PostAsync(url, body)
...
|> postAsync httpClient "/DoSomething"
This is usually my preferred option: I always wrap .NET APIs in F# form before using them. This is better, because the same wrapper can transform more than just parameters, but also other things, such as error handling or, in your case, async models:
let postAsync client url body =
client.PostAsync(url, body)
|> Async.AwaitTask
Option 3: go super general and make yourself a function for transforming any functions from non-curried to curried. In other functional languages such function is usually called uncurry:
let uncurry f a b = f (a, b)
...
|> uncurry httpClient.PostAsync "/DoSomething"
One problem with this is that it only works for two parameters. If you have a non-curried function with three parameters, you'd have to create a separate uncurry3 function for it, and so on.
In F#, you often need to work with .NET APIs that are not designed to work well as functional pipelines. In those cases, you can do various tricks to fit it into an (often very ugly) pipeline, or you can use the fact that F# is multi-paradigm and write the code in a more object-oriented style.
In your example, I would just use more C#-like style, because the code is not very pipeline-friendly:
async {
let serialized = JsonConvert.SerializeObject(someData)
let postData = new StringContent(serialized)
let! response = httpClient.PostAsync("/DoSomething", postData) |> Async.AwaitTask
}
I think there is also a good theoretical reason why this should not be a pipe - typically, pipelines work well if you have some "main entity" that you are transforming through a series of operations. This can often be some generic type such as list<'a> or non-generic type like Chart.
In your example, you start with object, turn it into JSON, then turn that into StringContent, then Task<'T> etc. - in other words, it's not transforming an entity - it's just doing a lot of unrelated things. In those situations, I prefer to use more explicit coding style rather than pipe.
It seems like there are two ways to return errors in an async workflow: raise and Result.
let willFailRaise = async {
return raise <| new Exception("oh no!")
}
let willFailResult = async {
return Result.Error "oh no!"
}
For the caller, the handling is a bit different:
async {
try
let! x = willFailRaise
// ...
with error ->
System.Console.WriteLine(error)
}
async {
let! maybeX = willFailResult
match maybeX with
| Result.Ok x ->
// ...
| Result.Error error ->
System.Console.WriteLine(error)
}
My questions are:
What are the advantages / disadvantages of each approach?
Which approach is more idiomatic F#?
It depends on what kind of error we are talking about. Basically there are three kinds:
Domain errors (e.g. user provided invalid data, user with this email is already registered, etc.)
Infrastructure errors (e.g you can't connect to another microservice or DB)
Panics (e.g. NullReferenceExceptionor StackOverflowException etc.), which are caused by programmers' mistakes.
While both approaches can get the job done, usually your concern should be to make your code as self-documented and easy-to-read as possible. Which means the following:
Domain errors: definitely go for Result. Those "errors" are expected, they are part of your workflow. Using Result reflects your business rules in function's signature, which is very useful.
Infrastructure failures: it depends. If you have microservices, then probably those failures are expected and maybe it would be more convenient to use Result. If not -- go for exceptions.
Panics: definitely Exception. First of all, you can't cover everything with Result, you gonna need global exception filter either way. Second thing -- if you try to cover all possible panics - code becomes a nasty disaster extremely fast, that will kill the whole point of using Result for domain errors.
So really this has nothing to do with Async or C# interop, it's about code readability and maintainability.
As for C# iterop -- don't worry, Result has all the methods to help, like IsError and so on. But you can always add an extension method:
[<AutoOpen>]
module Utils =
type Result<'Ok, 'Error> with
member this.Value =
match this with
| Ok v -> v
| Error e -> Exception(e.ToString()) |> raise
This is one of the many aspects of F# programming that suffers from the mind-split at the core of the language and its community.
On one hand you have "F# the .NET Framework language" where exceptions are the mechanism for handling errors, on the other - "F# the functional programming language" that borrows its idioms from the Haskell side of the world. This is where Result (also known as Either) comes from.
The answer to the question "which one is idiomatic" will change depending who you ask and what they have seen, but my experience has taught me that when in doubt, you're better off using exceptions. Result type has its uses in moderation, but result-heavy programming style easily gets out of hand, and once that happens it's not a pretty sight.
Raise
Advantages
Better .NET interop as throwing exceptions is fairly common in .NET
Can create custom Exceptions
Easier to get the stack trace as it's right there
You probably have to deal with exceptions from library code anyways in most standard async operations such as reading from a webpage
Works with older versions of F#
Disadvantages:
If you aren't aware of it potentially throwing an exception, you might not know to catch the exception. This could result in runtime explosions
Result
Advantages
Any caller of the async function will have to deal with the error, so runtime explosions should be avoided
Can use railway oriented programming style, which can make your code quite clean
Disadvantages
Only available in F# 4.1 or later
Difficult for non-F# languages to use it
The API for Result is not comprehensive.
There are only the functions bind, map, and mapError
Some functions that would be nice to have:
bimap : ('TSuccess -> 'a) -> ('TError -> 'e) -> Result<'TSuccess,'TError> -> Result<'a, 'e>
fold : ('TSuccess -> 'T) -> ('TError -> 'T) -> Result<'TSuccess, 'TError> -> 'T
isOk
Please unwrap these type signatures to help me understand why this doesn't work.
Then, if you have a solution, that would be great too.
I have this code and the agent.Post command has the signature Observer.Create<'T>(onNext: Action<'T>) : IObserver<'T>
let reservatinoRequestObserver = Observer.Create agent.Post
interface IHttpControllerActivator with
To my knowledge, this means that Observer.Create should take an Action with a single generic parameter and then return an IObserver.
Now the definition of Post is member MailboxProcessor.Post : message:'Msg ->unit
So... Post is a method, no? It is a method that takes a single parameter no? And it returns void no? So shouldn't it be a candidate for Observer.Create? Isn't that the exact specification of Action<'T>?
Well, somethings up, I get This function takes too many arguments, or is used in a context where a function is not expected:
Help me out... I freely admit I suck at F#
First, agent.Post returns unit, which is a different thing from void. F# will usually convert back and forth between void and unit for you, but they are not the same thing.
Second, F# functions do not implicitly convert to .NET delegates.
But there are some ways to do it:
You can explicitly create the delegate using its constructor:
let o = Observer.Create (new Action<_>( agent.Post ))
Lambdas are nicely wrapped too
let o = Observer.Create (fun msg -> agent.Post msg)
Use F# Rx-wrappers
Also there are a couple of F# wrappers/interop for Rx on nuget - just have a look, I think any will do
I want to create a couple of computational expressions that would be used to access the database and return a list of items like so (I also have questions in the code comments):
let foo x y z = proc "foo" {
let! cmd = proc.CreateCommand() // can I do this?
do! In "x" DbType.Int32 // would i gain anything by replacing DbType with a union
// type since the names would match actual data types?
do! In "y" DbType.String 15;
cmd?x <- x
cmd?y <- y
use! r = cmd.ExecuteReader() // would this be bad form for creating a workflow builder?
return! r {
let item = MyItem()
do! item.a <- r.GetInt32("a")
do! item.a <- r.GetString("b")
do! item.c <- r.GetDateTime("c")
yield! item
}
}
How can I create a workflow builder such that an instance of it takes a parameter?
let proc name = ProcedureBuilder(connStr, factory) // how do I do this?
Yes, you can do this. You can use computation expression syntax after any expression with a type statically known to expose the right methods. So the following code works (but doesn't do anything particularly interesting):
let f x = async
let v = f "test" { return 1 }
Here, f has type 'a -> AsyncBuilder, so f "test" has type AsyncBuilder and can be followed with computation expression syntax. Your example of let proc name = ProcedureBuilder(connStr, factory) is perfectly fine, assuming that ProcedureBuilder is defined appropriately, though you presumably want name to appear somewhere in the constructor arguments.
The answer from Keith (kvb) is correct - you can use parameterized computation builders. The syntax of computation expressions is:
<expr> { <cexpr> }
So, the builder can be created by any expression. Usually, it is some value (e.g. async) but it can be a function call or even a constructor call. When using this, you would typically define a parameterized builder and then pass the argument to a constructor using a function (as #kvb suggests).
I actually wrote an example of this, not a long time ago, so I can share an example where - I think - this is quite useful. You can find it on F# snippets: http://fssnip.net/4z
The example creates a "special" asynchronous computation builder for ASP.NET MVC that behaves just like standard async. The only difference is that it adds Run member that uses AsyncManager (provided by ASP.NET) to execute the workflow.
Here are some relevant parts from the snippet:
/// A computation builder that is almost the same as stnadard F# 'async'.
/// The differnece is that it takes an ASP.NET MVC 'AsyncManager' as an
/// argumnet and implements 'Run' opration, so that the workflow is
/// automatically executed after it is created (using the AsyncManager)
type AsyncActionBuilder(asyncMgr:Async.AsyncManager) =
// (Omitted: Lots of boilerplate code)
/// Run the workflow automatically using ASP.NET AsyncManager
member x.Run(workflow) =
// Use 'asyncMgr' to execute the 'workflow'
The snippet wraps the construction in a base class, but you could define a function:
let asyncAction mgr = new AsyncActionBuilder(mgr)
And then use it to define asynchronous action in ASP.NET MVC:
member x.LengthAsync(url:string) = asyncAction x.AsyncManager {
let wc = new WebClient()
let! html = wc.AsyncDownloadString(url)
return html.Length }