How do you write a SelectMany from a Task in F# - f#

I would like to write a SelectMany monadic bind from a Task in F#. How would I write the following C# code which uses language-ext in F#?
Task<int> result = from task in Task.Run<int>(() => 40) select task + 2;

You can use the F# TaskBuilder library to get the F# computation expression (monadic syntax) for tasks. With this, you can rewrite your example as:
let result = task {
let! t = Task.Run<int>(() => 40)
return t + 2 }

Related

Is there an alternative to "let!" to support function chaining?

Is there an alternative to "let!" to support function chaining?
I currently have this:
async {
let! result = token |> queryDay
result |> toTransactions
}
However, I would like to consolidate the above code into something like this:
async {
// NOTE: Async.Await isn't a thing
let result = token |> queryDay |> Async.Await |> toTransactions
}
Is there a way to achieve this?
From your examples I'm assuming that:
queryDay : 'a -> Async<'b>
toTransactions : 'b -> Async<'c>
Chaining monadic functions like that is called "bind". This is the core operation of a monad, the very essense of it. In fact the let! construct gets desugared into a call to async.Bind, and so does do!.
Unfortunately, the F# standard library doesn't offer a built-in standalone implementation of bind for Async. But there is one in FSharpx that you can use:
open FSharpx.Control
async {
let! result = token |> queryDay |> Async.bind toTransactions
}
Or if you don't want to use FSharpx, you can easily make one yourself by delegating to the computation builder:
module Async =
let bind f a = async.Bind(a, f)

Reader monad transformer sample with FSharpPlus

I'm trying to understand the reader monad transformer. I'm using FSharpPlus and try to compile the following sample which first reads something from the reader environment, then performs some async computation and finally combines both results:
open FSharpPlus
open FSharpPlus.Data
let sampleReader = monad {
let! value = ask
return value * 2
}
let sampleWorkflow = monad {
do! Async.Sleep 5000
return 4
}
let doWork = monad {
let! envValue = sampleReader
let! workValue = liftAsync sampleWorkflow
return envValue + workValue
}
ReaderT.run doWork 3 |> Async.RunSynchronously |> printfn "Result: %d"
With this I get a compilation error at the line where it says let! value = ask with the following totally unhelpful (at least for me) error message:
Type constraint mismatch when applying the default type 'obj' for a type inference variable. No overloads match for method 'op_GreaterGreaterEquals'.
Known return type: Async
Known type parameters: < obj , (int -> Async) >
It feels like I'm just missing some operator somewhere, but I can't figure it out.
Your code is correct, but F# type inference is not that smart in cases like this.
If you add a type annotation to sampleReader it will compile fine:
let sampleReader : ReaderT<int,Async<_>> = monad {
let! value = ask
return value * 2
}
// val sampleReader : FSharpPlus.Data.ReaderT<int,Async<int>> =
// ReaderT <fun:sampleReader#7>
Update:
After reading your comments.
If what you want is to make it generic, first of all your function has to be declared inline otherwise type constraints can't be applied:
let inline sampleReader = monad ...
But that takes you to the second problem: a constant can't be declared inline (actually there is a way but it's too complicated) only functions can.
So the easiest is to make it a function:
let inline sampleReader () = monad ...
And now the third problem the code doesn't compile :)
Here again, you can give type inference a minimal hint, just to say at the call site that you expect a ReaderT<_,_> will be enough:
let inline sampleReader () = monad {
let! value = ask
return value * 2
}
let sampleWorkflow = monad {
do! Async.Sleep 5000
return 4
}
let doWork = monad {
let! envValue = sampleReader () : ReaderT<_,_>
let! workValue = liftAsync sampleWorkflow
return envValue + workValue
}
ReaderT.run doWork 3 |> Async.RunSynchronously |> printfn "Result: %d"
Conclusion:
Defining a generic function is not that trivial task in F#.
If you look into the source of F#+ you'll see what I mean.
After running your example you'll see all the constraints being generated and you'll probably noted how the compile-time increased by making your function inline and generic.
These are all indications that we're pushing F# type system to the limits.
Although F#+ defines some ready-to-use generic functions, and these functions can sometimes be combined in such a way that you create your own generic functions, that's not the goal of the library, I mean you can but then you're on your own, in some scenarios like exploratory development it might make sense.

Using IRepository interfaces in f#

I'm currently rewriting a graduate student project that was written in c# to f#.
I'm stumped on how to handle IRepository interfaces in f#. It seems trivial in c#, but f# doesn't like what I've done.
The IRepository in question is defined in the myNameSpace.SolarSystem name space. Which I make sure to include in my f# project.
Here are my notes:
f# - invalid use of an interface type <--(let repo = IRepository<SolarSystem>())
open myNameSpace.SolarSystem
let searchCatalog = [| 8; 11; 31 |]
let repo = IRepository<SolarSystem>()
let ClassOfSolarSystems classOfStar =
repo.Query().Where(fun s -> s.SolarGroups.Any(fun c -> searchCatalog.Contains(classOfStar) ))
c# - no error:
using myNameSpace.SolarSystem
private readonly int[] searchCatalog = new int[] { 8, 11, 31 };
public IRepository<SolarSystem> Repo { get; set; }
public IEnumerable<SolarSystem> ClassOfSolarSystems(Int32 classOfStar)
{
return Repo.Query()
.Where(s => s.SolarGroups.Any(c => searchCatalog.Contains(classOfStar)));
}
I exhausted my googlefu and could not find any meaningful(to me at least) solutions.
Is there a way to use IRepository interfaces in f#?
Thanks!
Your F# line is equivalent to this C#, as the keyword new is implicit in F#.
var repo = new IRepository<SolarSystem>()
The C# compiler would not let you do that either. Also, your C# example is a property, while in F# it is a value binding. To define properties in F# you need to use the member keyword.
Edit
I played around with the editor a bit until I found something the compiler was mildly happy about, came up with this.
let ClassOfSolarSystems (repo : IRepository<SolarSystem>) classOfStar =
repo.Query()
|> Seq.filter(fun s -> s.SolarGroups.Any(fun c -> searchCatalog.Contains(classOfStar) ))
I didn't mess too much with your LINQ expressions but you should consider using the F# Seq module instead.
When you write
let repo = IRepository<SolarSystem>()
you try to create an instance of the interface, as you well know, it is impossible.
Just create a function that takes a repository and search parameters.
open SolarSystems
open System.Linq
type RepositoryFunctions =
member this.ClassOfSolarSystems (repo:IRepository<SolarSystem>) (classOfStar:int32) =
repo.Query().Where(fun s -> s.SolarGroups.Any(fun c -> searchCatalog.Contains(classOfStar) ))
So, if you not prefer to use LINQ in F#, you can write:
open SolarSystems
type RepositoryFunctions =
member this.ClassOfSolarSystems (repo:IRepository<SolarSystem>) (classOfStar:int32) =
let catalogContainsStar searchCatalog = searchCatalog.Contains(classOfStar)
let systemContainsStar solarSys = solarSys.SolarGroups.Any( catalogContainsStar )
let getAllWithStar = Seq.filter systemContainsStar
in
repo.Query() |> getAllWithStar

How do I await an async method in F#

How do I await an async method in F#?
I have the following code:
type LegoExample() =
let brick = Brick(BluetoothCommunication("COM3"))
let! result = brick.ConnectAsync();
Error:
Unexpected binder keyword in member definition
Note, I reviewed the following link:
However, I only observe the functional technique and not the OOP technique.
you get the error because the let! construct (just like the do!) needs to be placed inside a computational workflow (like async { ...} but there are others - it's basically the syntactic sugar F# gives you for monads - in C# it would be the from ... select ... stuff LINQ came with and in Haskell it would be do ... blocks)
so assuming brick.ConnectAsync() will return indeed some Async<...> then you can wait for it using Async.RunSynchronously like this:
let brick = Brick(BluetoothCommunication("COM3"))
let result = brick.ConnectAsync() |> RunSynchronously
sadly a quick browser search on the page you linked did not find ConnectAsync so I cannot tell you exactly what the indent of the snippet was here but most likely you wanted to have this inside a async { ... } block like this:
let myAsyncComputation =
async {
let brick = Brick(BluetoothCommunication "COM3")
let! result = brick.ConnectAsync()
// do something with result ...
}
(note that I remove some unnecessary parentheses etc.)
and then you could use this myAsyncComputation
inside yet another async { .. } workflow
with Async.RunSynchronously to run and await it
with Async.Start to run it in background (your block needs to have type Async<unit> for this
with Async.StartAsTask to start and get a Task<...> out of it
...

The most appropriate way to return a hot, awaited task from F# to a caller in C# framework

It looks like if the following situation occurs often and I wonder
What would be the most appropriate and shortest F# equivalent (e.g. no extra tasks created, has the same SynchronizationContext etc.)?
Does the following have something that should be fixed or improved?
Here DoAsync is a member function derived from a framework class, it takes a parameter and returns a hot, awaited task to the caller that is some framework function.
In C#:
public async Task DoAsync(int x)
{
if(x == 10)
{
await taskContext.ReturnAsync();
}
}
Here Async.Ignore is from here
In F#:
member x.DoAsync(int x) =
async {
if x = 10
return! Async.AwaitTask(taskContext.ReturnAsync() |> Async.Ignore)
else
return! Async.AwaitTask(Task.FromResult(0))
} |> Async.StartAsTask :> Task
Look at Tomas' answer for a simpler way. As an added note, in F# 4.0 it looks like there's an overload for non-generic Task available. More details at this Visual F# Tools PR.
Using Async.AwaitTask and Async.StartAsTask is the way to go. Although you do not really need to return anything from the async if you just want to return a non-generic Task:
member x.DoAsync(x:int) =
let work = async {
if x = 10 then
do! taskContext.ReturnAsync() |> Async.Ignore }
Async.StartAsTask(work) :> Task

Resources