Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions EasyMonads.Test/EitherTests/QueryTests/IEnumerableSelectTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using NUnit.Framework;

namespace EasyMonads.Test.EitherTests.QueryTests
{
[TestFixture]
internal class IEnumerableSelectTests
{
[Test]
public void Select_Works_For_IEnumerable_Either()
{
Dictionary<int, string> resultDict = new Dictionary<int, string>
{
{ 0, "0" },
{ 1, "1" },
{ 2, "2" }
};

IEnumerable<Either<Unit, string>> results = from number in GetRange()
from text in ConvertToString(number)
select text;

foreach (var result in results.Select((x, i) => new { Value = x, Index = i }))
{
result.Value.DoRight(x => Assert.AreEqual(resultDict[result.Index], x));
result.Value.DoLeftOrNeither(Assert.Fail);
}

return;

IEnumerable<Either<Unit, int>> GetRange()
{
foreach (var entry in resultDict)
{
yield return entry.Key;
}
}

Either<Unit, string> ConvertToString(int number)
{
return number.ToString();
}
}

[Test]
public async Task Select_Works_For_Async_IEnumerable_Either()
{
Dictionary<int, string> resultDict = new Dictionary<int, string>
{
{ 0, "0" },
{ 1, "1" },
{ 2, "2" }
};

IEnumerable<Either<Unit, string>> results = await
from number in GetRangeAsync()

Check warning on line 58 in EasyMonads.Test/EitherTests/QueryTests/IEnumerableSelectTests.cs

View workflow job for this annotation

GitHub Actions / build

Operator 'from' cannot be used here due to precedence. Use parentheses to disambiguate.

Check warning on line 58 in EasyMonads.Test/EitherTests/QueryTests/IEnumerableSelectTests.cs

View workflow job for this annotation

GitHub Actions / build

Operator 'from' cannot be used here due to precedence. Use parentheses to disambiguate.
from text in ConvertToString(number)

Check failure on line 59 in EasyMonads.Test/EitherTests/QueryTests/IEnumerableSelectTests.cs

View workflow job for this annotation

GitHub Actions / build

An expression of type 'Either<Unit, string>' is not allowed in a subsequent from clause in a query expression with source type 'Task<IEnumerable<Either<Unit, int>>>'. Type inference failed in the call to 'SelectMany'.

Check failure on line 59 in EasyMonads.Test/EitherTests/QueryTests/IEnumerableSelectTests.cs

View workflow job for this annotation

GitHub Actions / build

An expression of type 'Either<Unit, string>' is not allowed in a subsequent from clause in a query expression with source type 'Task<IEnumerable<Either<Unit, int>>>'. Type inference failed in the call to 'SelectMany'.
select text;

foreach (var result in results.Select((x, i) => new { Value = x, Index = i }))
{
result.Value.DoRight(x => Assert.AreEqual(resultDict[result.Index], x));
result.Value.DoLeftOrNeither(Assert.Fail);
}

return;

Task<IEnumerable<Either<Unit, int>>> GetRangeAsync()
{
return resultDict.Select(x => Either<Unit, int>.FromRight(x.Key)).AsTask();
}

Either<Unit, string> ConvertToString(int number)
{
return Either<Unit, string>.From(number.ToString());
}
}
}
}
4 changes: 3 additions & 1 deletion EasyMonads/Either/EitherAsyncExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,9 @@ public static async Task<Either<TLeft, TResult>> Select<TLeft, TRight, TResult>(
neither: Either<TLeft, TResult>.Neither);
}

public static async Task<Either<TLeft, TResult>> SelectMany<TLeft, TRight, TIntermediate, TResult>(this Task<Either<TLeft, TRight>> either, Func<TRight, Task<Either<TLeft, TIntermediate>>> bind, Func<TRight, TIntermediate, TResult> project)
public static async Task<Either<TLeft, TResult>> SelectMany<TLeft, TRight, TIntermediate, TResult>(this Task<Either<TLeft, TRight>> either,
Func<TRight, Task<Either<TLeft, TIntermediate>>> bind,
Func<TRight, TIntermediate, TResult> project)
{
return await either.BindAsync(async right =>
await bind(right).BindAsync(delegate (TIntermediate intermediate)
Expand Down
105 changes: 105 additions & 0 deletions EasyMonads/Either/EitherEnumerableExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace EasyMonads
{
public static class EitherEnumerableExtensions
{
public static IEnumerable<Either<TLeft, TResult>> Select<TLeft, TRight, TResult>(this IEnumerable<Either<TLeft, TRight>> enumerableEither, Func<TRight, TResult> map)
{
return enumerableEither.Select(either => either.Map(map));
}

public static IEnumerable<Either<TLeft, TResult>> SelectMany<TLeft, TRight, TIntermediate, TResult>(this IEnumerable<Either<TLeft, TRight>> enumerableEither, Func<TRight, Either<TLeft, TIntermediate>> bind, Func<TRight, TIntermediate, TResult> project)
{
return enumerableEither.Select<Either<TLeft, TRight>, Either<TLeft, TResult>>(either => either.Bind<TResult>(right =>
bind(right).Bind<TResult>(intermediate => project(right, intermediate))));
}

public static IEnumerable<Task<Either<TLeft, TResult>>> SelectMany<TLeft, TRight, TIntermediate, TResult>(this IEnumerable<Task<Either<TLeft, TRight>>> enumerableAsyncEither,
Func<TRight, Task<Either<TLeft, TIntermediate>>> bind, Func<TRight, TIntermediate, TResult> project)
{
return enumerableAsyncEither.Select(async either => await either.BindAsync<TLeft, TRight, TResult>(right =>
bind(right).BindAsync<TLeft, TIntermediate, TResult>(intermediate => project(right, intermediate))));
}

/*
public static async IAsyncEnumerable<Either<TLeft, TResult>> SelectMany<TLeft, TRight, TIntermediate, TResult>(
this IAsyncEnumerable<Either<TLeft, TRight>> enumerableEither,
Func<Either<TLeft, TRight>, IAsyncEnumerable<Either<TLeft, TIntermediate>>> bindAsync,
Func<Either<TLeft, TRight>, Either<TLeft, TIntermediate>, Either<TLeft, TResult>> project)
{
await foreach (Either<TLeft, TRight> either in enumerableEither)
{
await foreach (Either<TLeft, TIntermediate> intermediate in bindAsync(either))
{
yield return project(either, intermediate);
}
}
}

public static async IAsyncEnumerable<Either<TLeft, TResult>> SelectMany<TLeft, TRight, TIntermediate, TResult>(
this IAsyncEnumerable<Either<TLeft, TRight>> enumerableEither,
Func<TRight, Either<TLeft, TIntermediate>> bind,
Func<TRight, TIntermediate, TResult> project)
{
await foreach (var either in enumerableEither)
{
yield return await either.BindAsync<TResult>(async right => bind(right).Bind(delegate(TIntermediate intermediate)
{
Either<TLeft, TResult> projection = project(right, intermediate);
return projection;
}));
}
}

public static async IAsyncEnumerable<Either<TLeft, TResult>> SelectMany<TLeft, TRight, TIntermediate, TResult>(
this IAsyncEnumerable<Either<TLeft, TRight>> enumerableEither,
Func<TRight, Either<TLeft, TIntermediate>> bind,
Func<TRight, TIntermediate, TResult> project)
{
await foreach (var either in enumerableEither)
{
yield return await either.BindAsync<TResult>(right => bind(right).BindAsync(delegate(TIntermediate intermediate)
{
Either<TLeft, TResult> projection = project(right, intermediate);
return projection.AsTask();
}));
}
}
*/

public static async Task<IEnumerable<Either<TLeft, TResult>>> Select<TLeft, TRight, TResult>(this Task<IEnumerable<Either<TLeft, TRight>>> asyncEnumerableEither, Func<TRight, TResult> map)
{
return (await asyncEnumerableEither).Select(map);
}

public static async Task<IEnumerable<Either<TLeft, TResult>>> SelectMany<TLeft, TRight, TResult>(this Task<IEnumerable<Either<TLeft, TRight>>> asyncEnumerableEither,
Func<TRight, Either<TLeft, Func<TRight, Either<TLeft, TResult>>>> bind,
Func<TRight, Func<TRight, Either<TLeft, TResult>>, TResult> project)
{
return (await asyncEnumerableEither).Select(either =>
{
return either.Bind<TResult>(right =>
bind(right).Bind(delegate(Func<TRight, Either<TLeft, TResult>> intermediate)
{
Either<TLeft, TResult> projection = project(right, intermediate);
return projection;
}));
});
}

public static IEnumerable<Task<Either<TLeft, TResult>>> SelectMany<TLeft, TRight, TIntermediate, TResult>(this IEnumerable<Task<Either<TLeft, TRight>>> asyncEnumerableEither,
Func<TRight, Either<TLeft, TIntermediate>> bind,
Func<TRight, TIntermediate, TResult> project)
{
return asyncEnumerableEither.Select(asyncEither => asyncEither.BindAsync(right => bind(right).Bind(delegate(TIntermediate intermediate)
{
Either<TLeft, TResult> projection = project(right, intermediate);
return projection;
})));
}
}
}
Loading