-
Notifications
You must be signed in to change notification settings - Fork 64
Description
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.