Let's consider I've function loadCustomerProjection:
let loadCustomerProjection id =
use session = store.OpenSession()
let result =
session.Load<CustomerReadModel>(id)
match result with
| NotNull -> Some result
| _ -> None
session.Load is synchronous and returns a CustomerReadModel
session also provides a LoadAsync method which I'm been using like this:
let loadCustomerProjection id =
use session = store.OpenSession()
let y = async {
let! x = session.LoadAsync<CustomerReadModel>(id) |> Async.AwaitTask
return x
}
let x = y |> Async.RunSynchronously
match x with
| NotNull -> Some x
| _ -> None
What I'm trying to understand:
Does the second version even make sense and does it add any value in terms of non blocking behavior as both have the same signature: Guid -> CustomerReadModel option?
Would it make more sense to have this signature Guid -> Async<CustomerReadModel> if loadCustomerProjection is called from with an Giraffe HttpHandler?
Or considering the Giraffe context, would be even better to have the signature Guid -> Task<CustomerReadModel>?
In my Giraffe handler what I want to do at least is to handle a null result via pattern matching as 404 - so at some point I need to have an |> Async.AwaitTask call anyway.
In this particular case there is no difference between your first and second version, except that you go through all the hoops in the second version to call the async function and then immediately wait for it. But the second version blocks exactly like the first one does.
As for the hot vs cold comments in the other answers; Because you wrapped the call to LoadAsync in an async computation expression, it stays cold (because async expression only executes when it is run). If on the other hand you would write
let y =
session.LoadAsync<CustomerReadModel>(id)
|> Async.AwaitTask
Then the LoadAsync would start executing immediately.
If you want to support async operations then it would indeed make sense make the entire function async:
let loadCustomerProjection id =
async {
use session = store.OpenSession()
let! x = session.LoadAsync<CustomerReadModel>(id) |> Async.AwaitTask
match x with
| NotNull -> return Some x
| _ -> return None
}
Whether you would use Task or Async is up to you. Personally I prefer Async because it's native to F#. But in your case you might want to stick with Giraffe's decision to stick with Task to avoid conversions.
Since the main difference between a Task and an Async is that when you have a Task it is always Hot whereas the Async is Cold (until you decide to run it) it makes sense to work with Async in your backend code and then when it is time for Giraffe to use it, convert it into a Task or run it.
In your case you are just doing one thing. I imagine it is more useful to go full async if you have multiple async steps that you want to compose in some way.
See https://learn.microsoft.com/en-us/dotnet/fsharp/tutorials/asynchronous-and-concurrent-programming/async#combine-asynchronous-computations for example.
As mentioned in the other answer the main difference between Task and Async is that Tasks are started immediately whereas Asyncs must be started explicitly.
In the simple example above it wouldn't make much difference in returning the 'T, Async<'T>, or Task<'T>. My preference would probably be Task<'T> as that is what you are receiving in the function and it makes sense to continue propagating the Task<_> until the final point of use.
Note that when you are using Giraffe you should have access to TaskBuilder.fs which gives you a task { } computation expression in the FSharp.Control.Tasks.V2 module.
Related
I've been trying to figure out the idiomatic F# way to download a webpage asynchronously and handle any errors/HTTP failure codes, I think this is my closest attempt so far but I'm getting a type error on the Choice1Of2 line
I'd love to
a) Understand why this fails (I'm still learning F#)
b) Know if this is the right approach/how to make this work or if I'm completely on the wrong track here
FS0001 This expression was expected to have type
'Async<Choice<string,exn>>'
but here has type
'Choice<'a,'b>'
let fetchAsync url = async {
return! Async.Catch(async {
let! str = Http.AsyncRequestString(url)
return str })
}
let result = fetchAsync "http://www.example.bad"
match result with
| Choice1Of2 v -> logger.LogInformation("worked")
| Choice2Of2 ex -> logger.LogInformation("failed")
a) Why it fails
Your fetchAsync function returns an Async<Choice<_>> and you pattern match as if the function only returns Choice<_>. Unfortunately you can't pattern match on Async because that would be a blocking operation, exactly what Async tries move away from.
b) Idiomatic way of dealing with these things.
What you can do, however, is stay within the Async context and handle the failure within. F# provides (at least) two common ways to deal with this. E.g. you can use the async helper functions that allow you to write a pipeline:
let fetchAsyncPipeline (url: string) =
FSharp.Data.Http.AsyncRequestString(url)
|> Async.Catch
|> Async.map (function
| Choice1Of2 v -> Ok v
| Choice2Of2 e -> Error e.Message)
Unfortunately, Async.map is not yet included. But you can define it for yourself like this:
namespace global
[<RequireQualifiedAccess>]
module Async =
let map f xA =
async {
let! x = xA
return f x
}
Or, you can use F#'s computation expressions that provide syntactic sugar to write the above in a more imperative style:
let fetchAsyncCe (url: string) =
async {
try
return!
FSharp.Data.Http.AsyncRequestString(url)
|> Async.map Ok
with
| e -> return Error e.Message
}
In both these solutions, I converted the exception to F#'s result type, which I personally find the nicest way to deal with errors.
Finally, as indicated by brianberns, your expression is only wrapped in the Async type. But unlike C#'s Task, async computations represent the program how to calculate something, but that program has not yet started and you have to explicitly run the asynchronous operation. One of the ways to do this is to use Async.RunSynchronously:
Async.RunSynchronously (fetchAsyncCe "https://fsharpforfunandprofit.com/")
PS: You probably came across Scott Wlaschin's excellent F# for fun and profit, but if you didn't you should check it out. Personally, I've found it the best resource to teach you F# and functional programming in general.
The reason this doesn't compile is because you're never actually running the computation created by fetchAsync. Something like this should work instead:
let fetchAsync url =
Http.AsyncRequestString(url)
|> Async.Catch
|> Async.RunSynchronously
After a few more hours and a lot of coffee I have this
let fetchAsync2 (url: string) =
async { return! Async.Catch(Http.AsyncRequestString(url)) }
|> Async.RunSynchronously
let result = fetchAsync2 url
match result with
| Choice1Of2 html -> html
| Choice2Of2 error -> error.Message
This code works the way I want it to but I'll leave the question open in case anyone has a better solution
Merging my version and the one provided by #brianberns I think I like this one best?
let fetchAsync3 (url: string) =
Http.AsyncRequestString(url)
|> Async.Catch
|> Async.RunSynchronously
let result = fetchAsync3 url
match result with
| Choice1Of2 html -> html
| Choice2Of2 error -> error.Message
Currently, I have a function that receives raw data from the outside, process it, and sends it to a callback:
let Process callback rawData =
let data = rawData //transforming into actual data....
callback data
callback is a function 'T -> unit. In my case specifically, it's the Post function of a MailboxProcessor (being called like Process mailbox.Post rawData)
The process function is called multiple times, and each time I push the processed data into the mailbox queue. So far so good.
Now I want to change this code in a way I can publish this processed data to various consumers, using the rx extensions for FSharp (FSharp.Control.Reactive). This means that callback will be either an Observable, or a function that publishes to subscribers. How do I do this?
I found two options:
Create a class that implements IObservable, and pass that object to the Process function. I'd like to avoid creating classes if possible.
Use the Subject.behavior. This does exactly what I want, except it requires a initial state, which doesnt make sense semantically in this case, and apparently Subjects are frowned upon (from a link in the ReactiveX site http://davesexton.com/blog/post/To-Use-Subject-Or-Not-To-Use-Subject.aspx).
What would be the better way, from a functional programming perspective? Is there a better way?
Here's one idea: You can use an object expression to implement IObservable<_> without the overhead of an explicit class:
let createObservable subscribe =
{
new IObservable<_> with
member __.Subscribe(observer) =
subscribe observer
}
To use this, specify a subscribe function of type IObserver<_> -> IDisposable. No classes needed.
Using the observe { .. } computation builder works, but there is a function in the FSharp.Control.Reactive library that does the same thing:
open FSharp.Control.Reactive
let obs = Observable.ofSeq [1;2;3;4;5]
If I was using the observe { .. } computation builder, I'd also use the fact that it supports for loop, which makes your code a bit simpler:
let Process initialData = observe {
for x in initialData do yield x }
Got it. Fsharp reactive provides the keyword observe from the module FSharp.Control.Reactive.Builders. This allows you to create ad-hoc observables:
open FSharp.Control.Reactive.Builders
//In my real case, "initialData" is a byte stream and
//at each step I read a few bytes off of it
let Process initialData =
let rec loop data =
observe {
match data with
| x :: xs ->
yield x
yield! loop xs
| [] -> ()
}
loop initialData
let obs = Process ([1;2;3;4;5])
obs.Subscribe(fun d -> printfn "Consumer A: %A" d) |> ignore
obs.Subscribe(fun d -> printfn "Consumer B: %A" d) |> ignore
Threading.Thread.Sleep 1000
obs.Subscribe(fun d -> printfn "Late consumer: %A" d) |> ignore
Important to note that this creates a cold observable, so the Late consumer receives all events.
Just starting out with f#, I come OO C# background and I have the following code that reads a text file of uk postscodes, it then hits an api end point with post codes, I test the result to see if post is valid or not:
let postCodeFile = "c:\\tmp\\randomPostCodes.txt"
let readLines filePath = System.IO.File.ReadLines(filePath)
let lines = readLines postCodeFile
let postCodeValidDaterUrl = "https://api.postcodes.io/postcodes/"
let validatePostCode postCode =
Request.createUrl Get (postCodeValidDaterUrl + postCode)
|> getResponse
|> run
let translateResponse response =
match response.statusCode with
| 200 -> true
| _ -> false
let validPostCode = validatePostCode >> translateResponse
lines |> Seq.iter(fun x -> validPostCode(x) |> printfn "%s-%b" x)
Any suggestions on making it more functional?
Critique / code review
You've already made this about as functional as it can be. I'll go through your code and explain why your decisions were good, and in a few cases, where you could make minor improvements.
let postCodeFile = "c:\\tmp\\randomPostCodes.txt"
Good to have this as a named variable; in real code, this would of course be a parameter to the script or a function parameter. So having it as a named variable is useful.
let readLines filePath = System.IO.File.ReadLines(filePath)
This function isn't strictly necessary; since System.IO.File.ReadLines takes a single parameter, you would be able to pipe into it (e.g., postCodeFile |> System.IO.File.ReadLines |> Seq.iter(...). But I like the shorter name, so I'd probably write it this way as well.
let lines = readLines postCodeFile
I'd probably leave off creating the lines name, and instead do postCodeFile |> readLines |> Seq.iter (...) in the last line of your code. There's nothing inherently wrong with the way you've done it, but you don't use the lines variable anywhere else so there's no real reason to give it a name. F#'s pipes allow you to skip naming your intermediate steps.
let postCodeValidDaterUrl = "https://api.postcodes.io/postcodes/"
Again, good to give this a name so that you can turn it into a parameter or a config file variable later. Only thing I see here that could be improved is the spelling: ValidDater should have been Validator.
let validatePostCode postCode =
Request.createUrl Get (postCodeValidDaterUrl + postCode)
|> getResponse
|> run
Looks good.
let translateResponse response =
match response.statusCode with
| 200 -> true
| _ -> false
Could be simpler: let translateResponse response = (response.statusCode = 200). But the match expression lets you expand it later if you have an API that could return other status codes, like 204, to indicate success as well. I'd probably go with the simpler comparison here, and add the match statement only if it's needed.
let validPostCode = validatePostCode >> translateResponse
Nice.
lines |> Seq.iter(fun x -> validPostCode(x) |> printfn "%s-%b" x)
As I mentioned earlier, lines is an intermediate step, so I'd probably change this to postCodeFile |> readLines |> Seq.iter (...) since that allows you to skip giving names to your intermediate steps.
Why this is good
Two things you did well here:
You wrote each function to do just one thing, and composed functions together to create larger "building blocks" of code. E.g., validatePostCode just sends off a request, and a different function decides whether the response indicates a valid code. This is good.
You separated (as much as you could) your I/O from your business logic. Specifically, the part of the code that validates the post codes doesn't try to read them in, or write out the results; it just says "Is this valid, or not?" That means that if you later need to swap out the API you call, or if you can do some internal checking on post codes that doesn't need to go hit the outside world, you can swap that out easily later. It's usually good practice to write your code in "layers", with I/O as the "outside" layer of your code, validation just "inside" the I/O layer, and then business logic inside the validation layer — so that your business-logic code can trust that it has received only valid data. You don't have any business logic in this simple example, but you have the I/O and validation layers properly separated. Well done.
I don't think the aim here should be to make the code "more functional". Being functional is not an inherent value. In F#, it makes sense to keep the core of your logic functional, but if you are doing a lot of I/O, then it makes sense to follow more imperative style.
My version of your code would look like this (somewhat overlapping with some suggestions by #rmunn):
let postCodeFile = "c:\\tmp\\randomPostCodes.txt"
let postCodeValidDaterUrl = "https://api.postcodes.io/postcodes/"
let lines = System.IO.File.ReadLines(postCodeFile)
let validatePostCode postCode =
Request.createUrl Get (postCodeValidDaterUrl + postCode)
|> getResponse
|> run
let translateResponse response =
response.statusCode = 200
for line in lines do
let valid = translateResponse (validatePostCode line)
printfn "%s-%b" line valid
My changes are:
I removed the readLines helper and just call File.ReadLines directly. There is no need to introduce F# alias for .NET methods if it does not serve some greater purpose like providing a more F#-friendly API that is reused in multiple places.
Like #rmunn, I replaced the match with response.statusCode = 200. I only use match when I need to bind new variables as part of matching. When just testing Boolean conditions, I think if is better.
I replaced your composed function and Seq.iter with a normal for loop. The code is imperative anyway, so I do not see why you wouldn't want to use a built-in language construct. I eliminated validPostCode because you're only using the composed function in one place, so introducing it does not simplify code.
This is just my style, it is not necessarily more functional or better:
open System.IO
let postCodeFile = "c:\\tmp\\randomPostCodes.txt"
let postCodeValidDaterUrl = "https://api.postcodes.io/postcodes/"
let validatePostCode postCode =
Request.createUrl Get (postCodeValidDaterUrl + postCode)
|> getResponse
|> run
|> fun response -> response.statusCode = 200
File.ReadLines postCodeFile
|> Seq.iter (fun code -> validatePostCode code |> printfn "%s-%b" code )
I need my state to be passed along while being able to chain functions with the maybe workflow. Is there a way for 2 workflows to share the same context? If no, what is the way of doing it?
UPDATE:
Well, I have a state that represents a segment of available ID's for the entities that I am going to create in the database. So once an ID is acquired the state has to be transformed to a newer state with the next available ID and thrown away so that nobody can use it again. I don't want to mutate the state for the sake of being idiomatic. The State monad looks like a way to go as it hides the transformation and passes the state along. Once the state workflow is in place I cannot use the Maybe workflow which is something I use everywhere.
As stated in the previous answer, one way to combine workflows in F# (Monads in Haskell) is by using a technique called Monad Transformers.
In F# this is really tricky, here is a project that deals with that technique.
It's possible to write the example of the previous answer by automatically combining State and Maybe (option), using that library:
#r #"c:\packages\FSharpPlus-1.0.0\lib\net45\FSharpPlus.dll"
open FSharpPlus
open FSharpPlus.Data
// Stateful computation
let computation =
monad {
let! x = get
let! y = OptionT (result (Some 10))
do! put (x + y)
let! x = get
return x
}
printfn "Result: %A" (State.eval (OptionT.run computation) 1)
So this is the other alternative, instead of creating your custom workflow, use a generic workflow that will be automatically inferred (a-la Haskell).
In F# you cannot easily mix different types of computation expressions as you would do in Haskell by using Monad Transformers or similar techniques. You could however build your own Monad, embedding state threading and optional values, as in:
type StateMaybe<'T> =
MyState -> option<'T> * MyState
// Runs the computation given an initial value and ignores the state result.
let evalState (sm: StateMaybe<'T>) = sm >> fst
// Computation expression for SateMaybe monad.
type StateMaybeBuilder() =
member this.Return<'T> (x: 'T) : StateMaybe<'T> = fun s -> (Some x, s)
member this.Bind(sm: StateMaybe<'T>, f: 'T -> StateMaybe<'S>) = fun s ->
let mx,s' = sm s
match mx with
| Some x -> f x s'
| None -> (None, s)
// Computation expression builder.
let maybeState = new StateMaybeBuilder()
// Lifts an optional value to a StateMaybe.
let liftOption<'T> (x: Option<'T>) : StateMaybe<'T> = fun s -> (x,s)
// Gets the current state.
let get : StateMaybe<MyState> = fun s -> (Some s,s)
// Puts a new state.
let put (x: MyState) : StateMaybe<unit> = fun _ -> (Some (), x)
Here's an example computation:
// Stateful computation
let computation =
maybeState {
let! x = get
let! y = liftOption (Some 10)
do! put (x + y)
let! x = get
return x
}
printfn "Result: %A" (evalState computation 1)
StateMaybe may be generalized further by making the type of the state component generic.
Others already gave you a direct answer to your question. However, I think that the way the question is stated leads to a solution that is not very idiomatic from the F# perspective - this might work for you as long as you are the only person working on the code, but I would recommend against doing that.
Even with the added details, the question is still fairly general, but here are two suggestions:
There is nothing wrong with reasonably used mutable state in F#. For example, it is perfectly fine to create a function that generates IDs and pass it along:
let createGenerator() =
let currentID = ref 0
(fun () -> incr currentID; !currentID)
Do you really need to generate the IDs while you are building the entities? It sounds like you could just generate a list of entities without ID and then use Seq.zip to zip the final list of entities with list of IDs.
As for the maybe computation, are you using it to handle regular, valid states, or to handle exceptional states? (It sounds like the first, which is the right way of doing things - but if you need to handle truly exceptional states, then you might want to use ordinary .NET exceptions).
What's the status of the Run() method in a computation method? I've seen it in several examples (here, here, here), and I've seen in it F#'s compiler source, yet it's not in the spec or the MSDN documentation. I filed an issue in MS Connect about this and it was closed as "by design" without further explanations.
So is it deprecated/undocumented/unsupported? Should I avoid it?
UPDATE: MS Connect issue status was promptly changed and the MSDN page updated to include Run()
6.3.10 Computation Expressions
More specifically, computation
expressions are of the form
builder-expr { cexpr } where cexpr is,
syntactically, the grammar of
expressions with the additional
constructs defined in comp-expr.
Computation expressions are used for
sequences and other non-standard
interpretations of the F# expression
syntax. The expression builder-expr {
cexpr } translates to
let b = builder-expr in b.Run (b.Delay(fun () -> {| cexpr |}C))
for a fresh variable b. If no method Run exists on the inferred type of b when this
expression is checked, then that call is omitted. Likewise, if no method Delay exists on > the type of b when this expression is checked, then that call is omitted
I think that the Run method was added quite late in the development process, so that's probably a reason why it is missing in the documentation. As desco explains, the method is used to "run" a computation expression. This means that whenever you write expr { ... }, the translated code will be wrapped in a call to Run.
The method is a bit problematic, because it breaks compositionality. For example, it is sensible to require that for any computation expression, the following two examples represents the same thing:
expr { let! a = foo() expr { let! c = expr {
let! b = bar(a) let! a = foo()
let! c = woo(b) let! b = bar(a)
return! zoo(c) } return! woo(b) }
return! zoo(c) }
However, the Run method will be called only on the overall result in the left example and two times on the right (for the overall computation expression and for the nested one). A usual type signature of the method is M<T> -> T, which means that the right code will not even compile.
For this reason, it is a good idea to avoid it when creating monads (as they are usually defined and used e.g. in Haskell), because the Run method breaks some nice aspects of monads. However, if you know what you are doing, then it can be useful...
For example, in my break code, the computation builder executes its body immediately (in the declaration), so adding Run to unwrap the result doesn't break compositionality - composing means just running another code. However, defining Run for async and other delayed computations is not a good idea at all.