swlaschin / Railway-Oriented-Programming-Example

This repository contains code that demonstrates the "Railway Oriented Programming" concept for error handling in functional programming languages.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Idea of concatenating original result 'a and new result 'b into a RopResult<('a, 'b), 'c>

raymens opened this issue · comments

This is meant as a suggestion and question at the same time, I'm very interested about your thoughts on using ROP and DDD for this.

One of my DAL functions is dependent on multiple tables which I have seperated into multiple DALs. Instead of copying these functions etc., I wanted them to accept an entity in the DAL function.

Like: GroupDao.Create(groupDomainModel, user)

Where the groupDomainModel is converted from a DTO supplied by input. And the user is derived from login info. So this user has to be derived prior to calling the GroupRepository.

So I created the function combineR listed below for this 'problem'.

/// Extension of bindR, the result of the function will be concatenated to the original result.
/// Creating a tuple.
let combineR (func : 'a -> RopResult<'c, 'b>) =
    let concat (functie : 'a -> RopResult<'c, 'b>) (arg : 'a) =
        match functie arg with
        | Success (pp, y) -> Success((arg, pp), y)
        | Failure(x) -> Failure(x)

    bindR (concat func)

This can then be used like this:

    let getUserAndCheckRules x = userDao.GetUserAndCheckRules this.User x.GroupDetails

    succeed group
    |> logSuccessR "POST with {0}"
    |> bindR DTOConverter.dtoToCreateGroup
    |> combineR getUserAndCheckRules
    |> bindR groupDao.CreateGroup
    |> logFailureR
    |> okR
    |> toHttpResult

Do you have any opinion about this?

(example is not code I'm using, but the best example I could think of)

And an additional method to support chaining multiple RopResults and rearranging (or discarding) them.
Don't mind the excessive type arguments ;)

let combine2R (comb : 'a * 'c -> 'd) (func : 'a -> RopResult<'TResult, 'TDomainMessages>) =
    let concat (functie : 'a -> RopResult<'TResult, 'TDomainMessages>) (arg : 'a) =
        match functie arg with
        | Success (result, msgs) -> Success((comb (arg, result)), msgs)
        | Failure(x) -> Failure(x)

    bindR (concat func)

Used like:

|> combineR (fun ((x), d) -> (x, d)) getUserAndCheckRules