Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AsyncArrow? #10

Open
eulerfx opened this issue Feb 24, 2015 · 1 comment
Open

AsyncArrow? #10

eulerfx opened this issue Feb 24, 2015 · 1 comment

Comments

@eulerfx
Copy link
Contributor

eulerfx commented Feb 24, 2015

The types:

type AsyncArrow<'a, 'b> = 'a -> Async<'b>

type AsyncFilter<'a, 'b, 'c, 'd> = AsyncArrow<'a, 'b> -> AsyncArrow<'c, 'd>

type AsyncFilter<'a, 'b> = AsyncArrow<'a, 'b> -> AsyncArrow<'a, 'b>

The async arrow type can have many interpretations and is particularly well suited at representing an async request-reply protocol. Data driven services are usually a composition of various request-reply interactions and it can be useful to reify the type.

The supported operations would be all those of arrows as seen here but also many others specific to Async and other types. Consider operations such as:

/// Invokes arrow g and then invokes f if successful (Choice1Of2).
val tryBefore (g:AsyncArrow<'a, Choice<'a, 'c>>) (f:AsyncArrow<'a, 'b>) : AsyncArrow<'a, Choice<'b, 'c>>

/// Creates an arrow which propagates its input into the output.
val strength (f:AsyncArrow<'a, 'b>) : AsyncArrow<'a, 'a * 'b>

/// Creates an arrow which filters inputs to the specified arrow.
val filterAsync (p:AsyncArrow<'a, bool>) (df:Async<'b>) (f:AsyncArrow<'a, 'b>) : AsyncArrow<'a, 'b>

Async filters represent mappings between arrows. A filter can be use to inject various cross-cutting concerns. For example, a timing filter:

  let timing (log:NLog.Logger) : AsyncFilter<_,_,_,_> =
    fun (f:AsyncArrow<'a, 'b>) a -> async { 
      let sw = System.Diagnostics.Stopwatch.StartNew()
      let! res = f a
      sw.Stop()
      log.Trace("Time Elapsed={0}", sw.ElapsedMilliseconds)
      return res 
    }

A filter can also change the input/output type of an arrow. This can be used for layering a JSON codec onto a request/reply protocol, for instance.

type AsyncSink<'a> = AsyncArrow<'a, unit>

A sink can be used to represent functions which are run solely for the side-effects. An example operation:

  let mergeAllPar (ss:seq<AsyncSink<'a>>) : AsyncSink<'a> =
    fun a -> ss |> Seq.map ((|>) a) |> Async.Parallel |> Async.Ignore
@eulerfx
Copy link
Contributor Author

eulerfx commented Feb 24, 2015

The paper Your Server as a Function explains the applications of these ideas to servers. The difference is mostly in the naming AsyncArrow is Service and AsyncFilter is Filter. Furthermore, they use Future abstraction which is similar to Async in terms of the operations it supports, but inherently different in that it is a promise (more like a TPL Task).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant