Skip to content

Instantly share code, notes, and snippets.

@Szer
Last active July 5, 2021 11:56
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Szer/d14fc836a5c305af736a121278bc8df4 to your computer and use it in GitHub Desktop.
Save Szer/d14fc836a5c305af736a121278bc8df4 to your computer and use it in GitHub Desktop.
This is a joke
type Effect<'env, 'out> = Effect of ('env -> 'out)
module Effect =
let value x = Effect (fun _ -> x)
let apply f = Effect f
let run env (Effect f) = f env
let run' (Effect f) env = f env
let map f (Effect g) = Effect(f << g)
let local f (Effect g) = Effect(f >> g)
let inline bind f effect =
Effect (fun env ->
let x = run env effect
run env (f x)
)
let map2 f x y =
Effect(fun env ->
let x = run env x
let y = run env y
f x y
)
let inline (^) f x = f x
let inline (>>-) x f = Effect.map f x
let inline (!>) x = Effect.value x
let inline (!>>) x = Effect.apply x
type ResultBuilder() =
member __.Return value = Result.Ok value
member __.ReturnFrom (result: Result<_,_>) = result
member __.Bind(result, fn) = Result.bind fn result
type EffectBuilder() =
member __.Return value = !> value
member __.Zero () = !> Unchecked.defaultof<_>
member __.ReturnFrom (effect: Effect<'env, 'out>) = effect
member __.Bind(effect, fn) = Effect.bind fn effect
let effect = EffectBuilder()
let result = ResultBuilder()
module Async =
let map f x = async.Bind(x, f >> async.Return)
let map2 f x y = async {
let! x = x
let! y = y
return f x y
}
module Result =
let traverseAsync: Result<Async<'a>,'b> -> Async<Result<'a,'b>> = function
| Result.Ok async -> Async.map Result.Ok async
| Error exn -> async.Return (Result.Error exn)
let traverseEffect = function
| Result.Ok effect -> Effect.map Result.Ok effect
| Error exn -> !> (Result.Error exn)
let flatten = function
| Result.Ok r -> r
| Error exn -> Error exn
let map2 f x y = result {
let! x = x
let! y = y
return f x y
}
type ReceiveRequest = class end
type ValidatedRequest = class end
type CanonicalizeEmail = class end
let receiveRequest: ReceiveRequest = failwith ""
let validateRequest: ReceiveRequest -> Result<ValidatedRequest, exn> = failwith ""
let canonicalizeEmail: ValidatedRequest -> Result<CanonicalizeEmail, exn> = failwith ""
let updateDbDromRequest: CanonicalizeEmail -> Async<Result<unit, exn>> = failwith ""
let sendEmail: ValidatedRequest -> Async<Result<unit, exn>> = failwith ""
let effectfulSendEmail: Effect<ValidatedRequest, Async<Result<unit, exn>>> =
!>> sendEmail
let effectfulCanonicalizeEmail: Effect<ValidatedRequest, Async<Result<unit, exn>>> =
!>> canonicalizeEmail
>>- Result.map updateDbDromRequest
>>- Result.traverseAsync
>>- Async.map Result.flatten
let combinedFlow: Effect<ValidatedRequest, Async<Result<unit, exn>>> =
(effectfulCanonicalizeEmail, effectfulSendEmail)
||> Effect.map2 ^Async.map2 ^Result.map2 ^fun () () -> ()
let updateCustomerFlow: Effect<ReceiveRequest, Async<Result<unit, exn>>> =
!>> validateRequest
>>- Result.map ^Effect.run' combinedFlow
>>- Result.traverseAsync
>>- Async.map Result.flatten
let updateCustomer: ReceiveRequest -> Async<Result<unit, exn>> =
Effect.run' updateCustomerFlow
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment