Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add 'Ensure' and 'Check' method similar to C#FunctionalExtensions #281

Open
PI-Gorbo opened this issue Oct 29, 2024 · 4 comments
Open

Comments

@PI-Gorbo
Copy link
Contributor

PI-Gorbo commented Oct 29, 2024

Hi! Loving the library. Using this library has felt very natural to me, as I use CSharpFunctionalExtensions all the time in C#.
I think the library identifies some helpful methods that could be useful in this library too, and I have highlighted them below.
If there are already more 'FSharp' style ways of approaching this, I am very open. I don't mind being wrong :)

Ensure

From the source code:

public static Result<T, E> Ensure<T, E>(this Result<T, E> result, Func<T, bool> predicate, Func<T, E> errorPredicate)
{
    if (result.IsFailure)
        return result;

    if (!predicate(result.Value))
        return Result.Failure<T, E>(errorPredicate(result.Value));

    return result;
}

Ensure allows you to evaluate a predicate. If the predicate is false, then return an error.

Example usage of ensure

Before:

let mapIdentityResult (res: Task<IdentityResult>) : Task<Result<unit, string>> =
    res
    |> TaskResult.ofTask
    >>= fun res ->
            if res.Succeeded then
                TaskResult.ok ()
            else
                res.Errors
                    |> Seq.map (fun x -> x.Description)
                    |> Seq.fold (fun item agg -> agg + ", " + item) ""
                    |> TaskResult.error

After:

let mapIdentityResult (res: Task<IdentityResult>) : Task<Result<unit, string>> =
    res
    |> TaskResult.ofTask
    |> TaskResult.ensure (fun res -> res.Succeeded) (fun res ->
                    res.Errors
                    |> Seq.map (fun x -> x.Description)
                    |> String.concat ", ")
    |> TaskResult.ignore

Check

From the source code:

public static Result<T, E> Check<T, K, E>(this Result<T, E> result, Func<T, Result<K, E>> func)
{
    return result.Bind(func).Map(_ => result.Value);
}

This method allows you to keep the calling success condition of the result.

Example usage of Check

Here is a code snippet that could utilize check

...
  |> TaskResult.bind (fun user ->
        if not user.EmailConfirmed then
            userManager.ConfirmEmailAsync(
                user,
                Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(request.ConfirmEmailToken))
            )
            |> mapIdentityResult
            |> TaskResult.mapError FailedToConfirm
            |> TaskResult.map (fun _  -> user)
        else
            TaskResult.ok user)
 |> ...

Here, using check would look like so:

...
  |> TaskResult.check(fun user ->
        if not user.EmailConfirmed then
            userManager.ConfirmEmailAsync(
                user,
                Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(request.ConfirmEmailToken))
            )
            |> mapIdentityResult
            |> TaskResult.mapError FailedToConfirm
        else
            TaskResult.ok)
 |> ...

I can appreciate here the code difference is small, but I think the semantic difference is helpful.

Again, I am new to f#, so if this is not the idiomatic way of doing things, then let me know - But if this is liked im happy to submit a PR.

@PI-Gorbo PI-Gorbo changed the title feat: Add 'Check' method similar to C#FunctionalExtensions feat: Add 'Ensure' and 'Check' method similar to C#FunctionalExtensions Oct 29, 2024
@TheAngryByrd
Copy link
Collaborator

👋 This look like good ideas! Go ahead a put a PR together so we can go over some more designs.

@PI-Gorbo
Copy link
Contributor Author

PI-Gorbo commented Dec 19, 2024

@TheAngryByrd Heyo! I've finished the first draft of the PR and its ready for review, but I can't seem to publish a branch
When i try and create a branch on origin using git push --set-upstream origin feat/AddCheckAndEnsure I get the following error.
{61D7087F-AEE4-4DBC-9DEC-FC66422476A7}

Do I need to do something special, otherwise do you mind granting permissions? Im not looking to have perms to merge anything, just to create a branch.

I am able to pull

@TheAngryByrd
Copy link
Collaborator

Great to hear!

It's because you don't have permission to push to demystifyfp. You'll have to create a fork of this repository, push to there, then create a PR with that branch on that fork.

@PI-Gorbo
Copy link
Contributor Author

PI-Gorbo commented Dec 22, 2024

Heyo! Thanks for being patient with me!
I have made a Fork and have a PR. #295

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants