How to switch from error track back to success track in railway-oriented program in F#?

夙愿已清 提交于 2019-12-11 10:16:09

问题


Using AsyncResult from Scott Wlashin and wondering how I can change from the error track to the success track.

Pseudo-code:

let orchestratorFunction() : AsyncResult<Customer, CustomerError> = asyncResult {

   let! output1 = callFunction1 arg1 arg2 |> AsyncResult.MapError CustomerError.Val1

   let! output2 = callFunction2 arg1 arg2 |> AsyncResult.MapError CustomerError.Val2

   let! output3 = callFunction3 arg1 arg2 |> AsyncResult.MapError (fun e -> ********HERE I WANT TO GET BACK TO THE SUCCESS PATH AND RETURN output3*********)

}

or a more realistic example: 

let createCustomer() : AsyncResult<Customer, CustomerError> = asyncResult {

   let! customerDto = mapDtoFromHttpRequest arg1 arg2 |> AsyncResult.MapError CustomerError.Val1

   let! validatedCustomer = validateCustomer arg1 arg2 |> AsyncResult.MapError CustomerError.Val2

   let! validatedCustomer = insertCustomer arg1 arg2 
      |> AsyncResult.MapError (fun e -> 
            match e with 
            | DuplicateCustomer _ -> 
                loadCustomerById xx 
                |> (fun c -> 
                      if c.LastCausationId = validatedCustomer.LastCausationId 
then c 
else e))
}

So basically I am trying to get out of the unhappy path, because this is an idempotent REST operation and any repetitive requests will be answered with 200 OK, as if they were the original request, so that the client can have a simple logic.


回答1:


Based on the answer from @Gus to this question (AsyncResult and handling rollback) it seems that bindError is what I needed. I created a similar to his bindError bindExn, and it seems to work as well, so now both error and exns can be converted to Ok:

(From Gus):

/// Apply a monadic function to an AsyncResult error  
let bindError (f: 'a -> AsyncResult<'b,'c>) (xAsyncResult : AsyncResult<_, _>) :AsyncResult<_,_> = async {
    let! xResult = xAsyncResult 
    match xResult with
    | Ok x -> return Ok x
    | Error err -> return! f err
}

(My code):

let bindExn
    (f: exn -> AsyncResult<'a,'b>)
    (xAsyncResult:AsyncResult<_,_>)
    : AsyncResult<'a,'b>
    =
    async {
        let! res =
            xAsyncResult
            |> Async.Catch
            |> Async.map(function
                | Choice1Of2 res -> res |> AsyncResult.ofResult
                | Choice2Of2 (ex:exn) ->
                    f ex
            )
        return! res
    }


来源:https://stackoverflow.com/questions/57922915/how-to-switch-from-error-track-back-to-success-track-in-railway-oriented-program

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!