Last active
October 30, 2015 22:52
-
-
Save eulerfx/f43792a19e6bfc50e0ba to your computer and use it in GitHub Desktop.
AOP the functional way in F#
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 } | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// 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