How would you build a new computation expression that inherits most behaviour from an existing one, but you might need to override some behaviour?
Context:
I will use CE as the abbreviation for computation expression from now on.
I'm using https://github.com/demystifyfp/FsToolkit.ErrorHandling
I have a "layered" application with a repository that fetches from a database layer.
All functions in the database layer so far return Task<Result<'T, DatabaseError>> via the taskResult { ... } CE from FsToolkit.ErrorHandling.
In the repository though, I always want to return Task<Result<'T, RepositoryError>>, where RepositoryError can easily be derived from DatabaseError, which means that most of my code looks like this:
let getAll con offset chunk = taskResult {
let! products =
ProductEntity.allPaginated offset chunk con
|> TaskResult.mapError RepositoryError.fromDatabaseError
let! totalCount =
ProductEntity.countAll con
|> TaskResult.mapError RepositoryError.fromDatabaseError
return { Items = products; TotalCount = totalCount }
}
The goal:
I would like to have all those TaskResult.mapError RepositoryError.fromDatabaseError calls be made under the hood inside a new CE. Let's call it repoTaskResult { ... }
I need to have all the current functionality of the original taskResult { ... } CE
let getAll con offset chunk = repoTaskResult {
let! products = ProductEntity.allPaginated offset chunk con
let! totalCount = ProductEntity.countAll con
return { Items = products; TotalCount = totalCount }
}
Edit:
A. Trying to solve it with inheritance (inferring the correct type does not work though)
type RepositoryTaskResultBuilder() =
inherit TaskResultBuilder()
member __.Bind(databaseTaskResult: Task<Result<'T, DatabaseError>>, binder) =
let repoTaskResult = databaseTaskResult |> TaskResult.mapError RepositoryError.fromDatabaseError
__.Bind(taskResult = repoTaskResult, binder = binder)
let repoTaskResult = RepositoryTaskResultBuilder()
Usage:
let getAll con offset chunk = repoTaskResult {
let! other = Task.singleton 1
let! products = ProductEntity.allPaginated offset chunk con
let! totalCount = ProductEntity.countAll con
return { Items = products; TotalCount = totalCount }
}
Conclusion for inheritance version:
Goal #2 is achieved easily, other is correctly inferred as int.
Goal #1 though is not achieved without any help for the type inference. By default let! seems to be inferred as one of the more generic Bind methods of the underlying TaskResultBuilder. That means that the whole return type is being inferred as Task<Result<'T, DatabaseError>>.
If you would help out the type inference by replacing the return statement with return! Result<_,RepositoryError>.Ok { Items = products; TotalCount = totalCount }, then you are good to go, as now the let! statements before are correctly using the newly implemented Bind method.
Related
seq is an alias of the IEnumerable interface, then you can create objects which implements IEnumerable and use its methods, for example:
IEnumerable<int> list = new List<int> { 1, 2, 3, 4, 5 };
and use the IEnumerable methods:
Where, Max, etc.
But you must instance an object that implements IEnumerable.
But... in F# you can create a sequence like:
let list = seq { for i in 1..5 -> i }
And Visual Studio says you list has the seq type. This is impossible, seq is an interface (IEnumerable) and you can't create an instance of an interface.
So, what's the magic inside seq?
Using GetType in FSI:
let goingToSee = seq { for i in 1..5 -> i }
goingToSee.GetType();;
val goingToSee : seq<int>
val it : System.Type = FSI_0010+goingToSee#12
The seq { .. } expression in F# is more similar to iterator methods in C# (written using the yield keyword) than to collection initializers. Similarly to the C# compiler handling of iterators, F# compiler turns the seq { .. } expression into a class that implements IEnumerable<T>.
The compiled class inherits from GeneratedSequenceBase (see the source code) and puts code generated based on what you wrote in the sequence expression. It is compiled as a state machine, so the code looks a bit ugly, but if you look at it using ILSpy, it looks something like this:
internal sealed class list#6 : GeneratedSequenceBase<int> {
public override int GenerateNext(ref IEnumerable<int> next) {
switch (this.pc) {
case 1: goto IL_82;
case 2: this.i = 0; break;
case 3: goto IL_A3;
default: {
this.#enum = Operators.OperatorIntrinsics.RangeInt32(1, 1, 5).GetEnumerator();
this.pc = 1;
break; }
}
if (this.#enum.MoveNext()) {
this.i = this.#enum.Current;
this.pc = 2;
this.current = this.i;
return 1;
}
IL_82:
this.pc = 3;
LanguagePrimitives.IntrinsicFunctions.Dispose<IEnumerator<int>>(this.#enum);
this.#enum = null;
this.pc = 3;
IL_A3:
this.current = 0;
return 0;
}
}
I will not try to decode this, but I think pc keeps the state of the state machine. Depending on this, it either initializes the iterator, moves to the next state, or disposes of any resources that might be used.
It's also worth noting that the 6 in the name list#6 is the line number from where this generated class comes from.
I am trying to learn F# and am in the process of converting some C# code to F#.
I have the following C# method:
public async Task<Foo> GetFooAsync(byte[] content)
{
using (var stream = new MemoryStream(content))
{
return await bar.GetFooAsync(stream);
}
}
Where bar is some private field and GetFooAsync returns a Task<Foo>.
How does this translate to F#?
Here is what I currently have:
member public this.GetFooAsync (content : byte[]) =
use stream = new MemoryStream(content)
this.bar.GetFooAsync(stream)
Which returns a Task.
In F#, asynchrony is represented by the async computation builder, which is not an exact analog of Task, but can generally be used in place of one:
member public this.GetFooAsync (content : byte[]) =
async {
use stream = new MemoryStream(content)
return! this.bar.GetFooAsync(stream) |> Async.AwaitTask
}
|> Async.StartAsTask
If you are converting async/await-intensive C# code to F#, it might get cumbersome because of the difference between F#'s async and Task and the fact that you always have to call Async.AwaitTask
To avoid that you can use FSharpx library, which has a task computation expression.
let tplAsyncMethod p = Task.Run (fun _ -> string p)
// awaiting TPL method inside async computation expression
let asyncResult = async {
let! value1 = tplAsyncMethod 1 |> Async.AwaitTask
let! value2 = tplAsyncMethod 2 |> Async.AwaitTask
return value1 + value2
}
// The same logic using task computation expression
open FSharpx.Task
let taskResult = task {
let! value1 = tplAsyncMethod 1
let! value2 = tplAsyncMethod 2
return value1 + value2
}
The result of asyncResult is Async<string> and the result of taskResult is Task<string>.
I'm just starting out with F# and .Net but after some Googling I didn't find examples of this. I apologize in advance if this is too simple.
I'm trying to query a database and do it asynchronously. For example, I have a function like so:
let queryExample name =
query {for f in foo do
where (f.name = name)
select f.name}
|> Seq.toList
Now, how would I make an async version of this? query doesn't return an Async<'a> type.
The answer will depend on what you're querying. Many data sources will expose something like a data context that enables running queries in different ways, but this isn't exposed directly on the IQueryable type (and is therefore not something that you can do directly with the result of a query { ... } expression.
As an example, if your foo is a LINQ-to-SQL Table<Foo>, then you can do something like this:
let queryExample name =
let q =
query { for f in foo do
where (f.name = name)
select f.name }
let cmd = foo.Context.GetCommand(q)
async {
let! reader = Async.AwaitTask (cmd.ExecuteReaderAsync())
return foo.Context.Translate<Foo>(reader)
}
This will return an Async<seq<Foo>>. If you'll be running lots of queries like this, then it's easy to extract the meat of this into a reusable mechanism.
I use FSharp.Data.Sql with success http://fsprojects.github.io/SQLProvider/
Seq.executeQueryAsync
Example below shows an easy syntax for doing this. Basically just create an async function with a query expression inside and return the result.
let data = [ 1; 5; 7; 11; 18; 21]
let getEvenInts = fun (arr : list<int> ) -> async {
let q = query {
for N in arr do
where (( N % 2 ) = 0)
select N
}
return q
}
let getOddInts = fun (arr : list<int> ) -> async {
let q = query {
for N in arr do
where (( N % 2 ) <> 0)
select N
}
return q
}
let evens = getEvenInts data |> Async.RunSynchronously
let odds = getOddInts data |> Async.RunSynchronously
printfn "Evens: %A Odds: %A" evens odds
Using C# - ASP.NET MVC 4, I can define an async controller action like:
public async Task<ActionResult> IndexWorks()
{
var data = await DownloadAsync("http://stackoverflow.com");
return Content(data);
}
Is there a way to do something similar, using F#?
I'm aware of that I could use the AsyncManager approach. I'm also aware of that #Tomas Petricek have made a quite neat AsyncActionBuilder, but it just feels like a lot of boilerplate, compared to the C# approach.
async/await uses Tasks, so you'll need to convert back and forth between Task object and F# Async objects. To convert from Task to Async, use Async.AwaitTask. To do the opposite use Async.StartAsTask. Your example becomes:
member x.IndexWorks() =
async {
let! data = Async.AwaitTask (DownloadAsync "http://stackoverflow.com")
return x.Content(data)
} |> Async.StartAsTask
Alternatively, instead of using the async computation expression, you can use a computation expression that works for Tasks out of the box. There's one in FSharpx:
let task = FSharpx.Task.TaskBuilder()
(...)
member x.IndexWorks() = task {
let! data = DownloadAsync "http://stackoverflow.com"
return x.Content(data)
}
It actually seems like a fellow programmer, Dmitry Morozov have made such thing possible. He have made a custom AsyncWorkflowController that makes it possible to return Async<ActionResult> from an ActionResult. The code for the AsyncWorkFlowController can be found at http://fssnip.net/5q.
However, his implementation makes it very difficult to debug, due to the fact that the stack trace wont be preserved when rethrowen in the custom controller. Therefore I've made a little change to make this possible:
member actionDesc.EndExecute(asyncResult) =
match endAsync'.Value(asyncResult) with
| Choice1Of2 value -> box value
| Choice2Of2 why ->
// Preserve the stack trace, when rethrow
ExceptionDispatchInfo.Capture(why).Throw()
obj() (* Satisfy return value *) } } }
Also I've changed the following line: new ReflectedControllerDescriptor(controllerType),
to new ReflectedAsyncControllerDescriptor(controllerType) - However this change is purely optional, as it wont make any difference. I just found it more logical to use the Async one.
The full code would then be:
open System
open System.Web.Mvc
open System.Web.Mvc.Async
open System.Runtime.ExceptionServices
open Unchecked
type AsyncWorkflowController() =
inherit AsyncController()
override __.CreateActionInvoker() =
upcast { new AsyncControllerActionInvoker() with
member __.GetControllerDescriptor(controllerContext) =
let controllerType = controllerContext.Controller.GetType()
upcast { new ReflectedAsyncControllerDescriptor(controllerType) with
member ctrlDesc.FindAction(controllerContext, actionName) =
let forwarder = base.FindAction(controllerContext, actionName) :?> ReflectedActionDescriptor
if(forwarder = null || forwarder.MethodInfo.ReturnType <> typeof<Async<ActionResult>>) then
upcast forwarder
else
let endAsync' = ref (defaultof<IAsyncResult -> Choice<ActionResult, exn>>)
upcast { new AsyncActionDescriptor() with
member actionDesc.ActionName = forwarder.ActionName
member actionDesc.ControllerDescriptor = upcast ctrlDesc
member actionDesc.GetParameters() = forwarder.GetParameters()
member actionDesc.BeginExecute(controllerContext, parameters, callback, state) =
let asyncWorkflow =
forwarder.Execute(controllerContext, parameters) :?> Async<ActionResult>
|> Async.Catch
let beginAsync, endAsync, _ = Async.AsBeginEnd(fun () -> asyncWorkflow)
endAsync' := endAsync
beginAsync((), callback, state)
member actionDesc.EndExecute(asyncResult) =
match endAsync'.Value(asyncResult) with
| Choice1Of2 value -> box value
| Choice2Of2 why ->
// Preserve the stack trace, when rethrow
ExceptionDispatchInfo.Capture(why).Throw()
obj() (* Satisfy return value *) } } }
Usage:
type TestController() =
inherit AsyncWorkflowController()
member x.IndexWorks() = async {
let startThread = Thread.CurrentThread.ManagedThreadId
let! data = asyncDownload "http://stackoverflow.com"
let endThread = Thread.CurrentThread.ManagaedThreadId
return ContentResult(Content = "Start = %i | End = %i" startThread endThread) :> ActionResult }
And to confirm that it actually does everything async, and is not blocking any thread from the ASP.NET Pool, use:
member x.IndexWorks() = async {
let startThread = Thread.CurrentThread.ManagedThreadId
let! data = asyncDownload "http://stackoverflow.com"
let endThread = Thread.CurrentThread.ManagaedThreadId
return ContentResult(Content = "Start = %i | End = %i" startThread endThread) :> ActionResult }
The start and end thread will differ, hence the start thread was put back into the pool, and a new was returned when the async operation had completed.
I think there might be a bunch of people trying to do something like
type SomeController() =
inherit ApiController()
member x.Get() =
let data = Download("http://stackoverflow.com")
x.Ok(data) :> IHttpActionResult // Using built in Ok, BadRequest, etc.
Where type Get() = unit -> Task<IHttpActionResult> as expected from a C# WebApi Controller
If you try to do it as the accepted answer suggests (while trying to use the built-in Ok, BadRequest, etc. methods) you run into
can't access protected members from within a lambda
To solve this I used the ExtensionMethods directly rather than try to do contort between async {} and Task that MVC is expecting
type SomeController() =
inherit ApiController()
member x.Get() = async {
let! data = DownloadAsync("http://stackoverflow.com") |> Async.AwaitTask
return System.Web.Http.Results.OkNegotiatedContentResult(data, x) :> IHttpActionResult // Pass in 'this' pointer (x) into extension method along with data
} |> Async.StartAsTask
This with the additional upcast :> IHttpActionResult you can also return different behavior BadRequest, etc from your model and still have it run async and the type signatures should work out and compile cleanly
Is it possible to call a method on a returned object using the pipeline infix operator?
Example, I have a .Net class (Class1) with a method (Method1). I can currently code it like this:
let myclass = new Class1()
let val = myclass.Method1()
I know I could also code it as such
let val = new Class1().Method1()
However I would like to do be able to pipeline it (I am using the ? below where I don't know what to do):
new Class1()
|> ?.Method1()
Furthermore, say I had a method which returns an object, and I want to only reference it if that method didn't return null (otherwise bail?)
new Class1()
|> ?.Method1()
|> ?? ?.Method2()
Or to make it clearer, here is some C# code:
public void foo()
{
var myclass = new Class1();
Class2 class2 = myclass.Method1();
if (class2 == null)
{
return;
}
class2.Method2();
}
You can define something similar to your (??) operator fairly easily (but operators can't start with a question mark):
let (~??) f x =
if (x <> null) then
f x
Unfortunately, your pipelined code will need to be a bit more verbose (also, note that you can drop the new keyword for calling constructors):
Class1()
|> fun x -> x.Method1()
Putting it all together:
Class1()
|> fun x -> x.Method1()
|> ~?? (fun x -> x.Method2())
Using a custom operator as 'kvb' suggests is definitely an option. Another approach that you may find interesting in this case is to define your own 'computation expression' that automatically performs the check for null value at every point you specify. The code that uses it would look like this:
open System.Windows.Forms
// this function returns (0) null, or (1) btn whose parent is
// null or (2) button whose parent is not null
let test = function
| 1 -> new Button(Text = "Button")
| 2 -> new Button(Text = "Button", Parent = new Button(Text = "Parent"))
| _ -> null
let res =
safe { let! btn = test(2) // specify number here for testing
// if btn = null, this part of the computation will not execute
// and the computation expression immediately returns null
printfn "Text = %s" btn.Text
let! parent = btn.Parent // safe access to parent
printfn "Parent = %s" parent.Text // will never be null!
return parent }
As you can see, when you want to use a value that can potentially be 'null', you use let! inside the computation expression. The computation expression can be defined so that it immediately returns null if the value is null and runs the rest of the computation otherwise. Here is the code:
type SafeNullBuilder() =
member x.Return(v) = v
member x.Bind(v, f) =
if v = null then null else f(v)
let safe = new SafeNullBuilder()
BTW: If you want to learn more about this, it is very similar to 'Maybe' monad in Haskell (or computation working with F# option type).