Skip to content

Handling errors within monad transformer stacks #301

Description

@NickDarvey

Edit: See this comment for more concise question and the answer to it.

I've got a delightful stack of monad transformers here:

type Operation<'TResult, 'TError>   = ReaderT<SqlConnection * SqlTransaction, ResultT<Async<Result<'TResult, 'TError list>>>>

and it works well working with it in computation expressions.

  let run
    (get        : 'TSubject -> Operation<'TState, 'TAppError>)
    (subj       : 'TSubject) : Operation<unit, 'TAppError> = monad {
    let! state = get subj |> map (fun x -> x) 
    return ()
  }

x here is 'TState which is lovely that map lifts that lambda all the way. However how do I do maps somewhere within the stack? Like transform the error type, represented here by transformToCommonErrorTypeN:

  let run
    (get        : 'TSubject -> Operation<'TState, 'TAppError>)
    (set        : 'TState   -> Operation<'TState, 'TOtherError>)
    (subj       : 'TSubject) : Operation<unit, 'TError> = monad {
    let! state = get subj |> transformToCommonErrorType1
    let state = state // ... interpret new state
    do! set subj state |> transformToCommonErrorType2
    return ()
  }

Given a function
'TAppError -> 'TError,
how do I lift that to a
Operation<'TResult, 'TAppError> -> Operation<'TResult, 'TError>

(i.e. ReaderT<SqlConnection * SqlTransaction, ResultT<Async<Result<'TResult, 'TAppError list>>>> -> ReaderT<SqlConnection * SqlTransaction, ResultT<Async<Result<'TResult, 'TError list>>>>.)

So far I have:

// AppError :: 'TAppError -> 'TError`
let! state = get subj |> (AppError |> List.map |> mapError |> Async.map |> ResultT.??? |> ReaderT.map)

but I'm not sure what I need at the ResultT.??? bit...

Side note: ResultT.map has an odd return type to my eye. Is ResultT<'``Monad<'Result<('T -> 'U),'E>>``> correct, or a mistaken type parameter name?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions