Skip to content

Instantly share code, notes, and snippets.

@eulerfx
Last active October 30, 2015 22:52
Show Gist options
  • Save eulerfx/f43792a19e6bfc50e0ba to your computer and use it in GitHub Desktop.
Save eulerfx/f43792a19e6bfc50e0ba to your computer and use it in GitHub Desktop.
AOP the functional way in F#
type Service<'Input, 'Output> = 'Input -> Async<'Output>
/// A filter is an aspect in the AOP sense.
type Filter<'Input, 'InputInner, 'OutputInner, 'Output> = 'Input-> Service<'InputInner, 'OutputInner> -> Async<'Output>
type Filter<'Input, 'Output> = 'Input-> Service<'Input, 'Output> -> Async<'Output>
type Continuation<'a,'r> = ('a -> 'r) -> 'r
module Continuation =
let bind (m:Continuation<'a, 'r>) k c = m (fun a -> k a c)
module Filter =
/// Composes two filters into one which calls the first one, then the second one.
let andThen (f2:Filter<_,_,_,_>) (f1:Filter<_,_,_,_>) : Filter<_,_,_,_> = fun input -> Continuation.bind (f1 input) f2
/// Applies a filter to a service returning a filtered service.
let apply (service:Service<_,_>) (filter:Filter<_,_,_,_>) : Service<_,_> = fun input -> filter input service
/// The identity filter which passes the input directly to the service and propagates the output.
let identity : Filter<_,_,_,_> = fun (input:'Input) (service:Service<_,_>) -> service input
/// Invokes a synchronous function before and after calling a service.
let beforeAfterSync (before:'Input -> unit) (after:('Input * 'Output) -> unit) : Filter<_,_,_,_> =
fun req (service:Service<_,_>) -> async {
do before req
let! res = service req
do after (req,res)
return res }
/// A service which echoes its input.
let echoService : Service<string, string> = fun str -> async.Return str
/// A filter which prints a "before" and "after" message to std out.
let printBeforeAndAfterFilter : Filter<string, string> =
Filter.beforeAfterSync (fun _ -> printfn "before") (fun _ -> printfn "after")
/// The original service wrapped with the filter and upon invocation, "before"
/// and "after" will be printed.
let echoService' : Service<string, string> = printBeforeAndAfterFilter |> Filter.apply echoService
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment