-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
#62 - Added pattern matching to Either type.
- Loading branch information
Showing
7 changed files
with
487 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
87 changes: 87 additions & 0 deletions
87
src/SuccincT/Unions/PatternMatchers/EitherPatternMatcher.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
using System; | ||
using SuccincT.Functional; | ||
using static SuccincT.Functional.TypedLambdas; | ||
|
||
namespace SuccincT.Unions.PatternMatchers | ||
{ | ||
internal sealed class EitherPatternMatcher<TLeft, TRight, TResult> : | ||
IEitherFuncPatternMatcher<TLeft, TRight, TResult>, | ||
IEitherActionPatternMatcher<TLeft, TRight>, | ||
IUnionFuncPatternMatcherAfterElse<TResult>, | ||
IUnionActionPatternMatcherAfterElse | ||
{ | ||
private readonly Either<TLeft, TRight> _either; | ||
|
||
private readonly MatchSelectorsForEither<TLeft, TRight, TResult> _selector = | ||
MatchSelectorsCreator.CreateEitherSelectors<TLeft, TRight, TResult>(); | ||
|
||
internal EitherPatternMatcher(Either<TLeft, TRight> either) => _either = either; | ||
|
||
IUnionFuncPatternCaseHandler<IEitherFuncPatternMatcher<TLeft, TRight, TResult>, TLeft, TResult> | ||
IEitherFuncPatternMatcher<TLeft, TRight, TResult>.Left() | ||
{ | ||
return new UnionPatternCaseHandler<IEitherFuncPatternMatcher<TLeft, TRight, TResult>, TLeft, TResult>( | ||
_selector.RecordAction, | ||
this); | ||
} | ||
|
||
IUnionFuncPatternCaseHandler<IEitherFuncPatternMatcher<TLeft, TRight, TResult>, TRight, TResult> | ||
IEitherFuncPatternMatcher<TLeft, TRight, TResult>.Right() | ||
{ | ||
return new UnionPatternCaseHandler<IEitherFuncPatternMatcher<TLeft, TRight, TResult>, TRight, TResult>( | ||
_selector.RecordAction, | ||
this); | ||
} | ||
|
||
IUnionFuncPatternMatcherAfterElse<TResult> IEitherFuncPatternMatcher<TLeft, TRight, TResult>.Else( | ||
Func<Either<TLeft, TRight>, TResult> elseFunc) | ||
{ | ||
_selector.RecordElseFunction(elseFunc); | ||
return this; | ||
} | ||
|
||
IUnionFuncPatternMatcherAfterElse<TResult> IEitherFuncPatternMatcher<TLeft, TRight, TResult>.Else( | ||
TResult elseValue) | ||
{ | ||
_selector.RecordElseFunction(Func((Either<TLeft, TRight> _) => elseValue)); | ||
return this; | ||
} | ||
|
||
TResult IEitherFuncPatternMatcher<TLeft, TRight, TResult>.Result() => _selector.ResultNoElse(_either); | ||
|
||
TResult IUnionFuncPatternMatcherAfterElse<TResult>.Result() => _selector.ResultUsingElse(_either); | ||
|
||
IUnionActionPatternCaseHandler<IEitherActionPatternMatcher<TLeft, TRight>, TLeft> | ||
IEitherActionPatternMatcher<TLeft, TRight>.Left() | ||
{ | ||
return new UnionPatternCaseHandler<IEitherActionPatternMatcher<TLeft, TRight>, TLeft, Unit>( | ||
_selector.RecordAction, | ||
this); | ||
} | ||
|
||
IUnionActionPatternCaseHandler<IEitherActionPatternMatcher<TLeft, TRight>, TRight> | ||
IEitherActionPatternMatcher<TLeft, TRight>.Right() | ||
{ | ||
return new UnionPatternCaseHandler<IEitherActionPatternMatcher<TLeft, TRight>, TRight, Unit>( | ||
_selector.RecordAction, | ||
this); | ||
} | ||
|
||
IUnionActionPatternMatcherAfterElse IEitherActionPatternMatcher<TLeft, TRight>.Else( | ||
Action<Either<TLeft, TRight>> elseAction) | ||
{ | ||
_selector.RecordElseAction(elseAction); | ||
return this; | ||
} | ||
|
||
IUnionActionPatternMatcherAfterElse IEitherActionPatternMatcher<TLeft, TRight>.IgnoreElse() | ||
{ | ||
_selector.RecordElseAction(Action((Either<TLeft, TRight> _) => { })); | ||
return this; | ||
} | ||
|
||
void IEitherActionPatternMatcher<TLeft, TRight>.Exec() => _selector.ExecNoElse(_either); | ||
|
||
void IUnionActionPatternMatcherAfterElse.Exec() => _selector.ExecUsingElse(_either); | ||
} | ||
} |
17 changes: 17 additions & 0 deletions
17
src/SuccincT/Unions/PatternMatchers/IEitherActionPatternMatcher.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
using System; | ||
|
||
namespace SuccincT.Unions.PatternMatchers | ||
{ | ||
public interface IEitherActionPatternMatcher<TLeft, TRight> | ||
{ | ||
IUnionActionPatternCaseHandler<IEitherActionPatternMatcher<TLeft, TRight>, TLeft> Left(); | ||
|
||
IUnionActionPatternCaseHandler<IEitherActionPatternMatcher<TLeft, TRight>, TRight> Right(); | ||
|
||
IUnionActionPatternMatcherAfterElse Else(Action<Either<TLeft, TRight>> elseAction); | ||
|
||
IUnionActionPatternMatcherAfterElse IgnoreElse(); | ||
|
||
void Exec(); | ||
} | ||
} |
17 changes: 17 additions & 0 deletions
17
src/SuccincT/Unions/PatternMatchers/IEitherFuncPatternMatcher.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
using System; | ||
|
||
namespace SuccincT.Unions.PatternMatchers | ||
{ | ||
public interface IEitherFuncPatternMatcher<TLeft, TRight, TResult> | ||
{ | ||
IUnionFuncPatternCaseHandler<IEitherFuncPatternMatcher<TLeft, TRight, TResult>, TLeft, TResult> Left(); | ||
|
||
IUnionFuncPatternCaseHandler<IEitherFuncPatternMatcher<TLeft, TRight, TResult>, TRight, TResult> Right(); | ||
|
||
IUnionFuncPatternMatcherAfterElse<TResult> Else(Func<Either<TLeft, TRight>, TResult> elseAction); | ||
|
||
IUnionFuncPatternMatcherAfterElse<TResult> Else(TResult value); | ||
|
||
TResult Result(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
81 changes: 81 additions & 0 deletions
81
src/SuccincT/Unions/PatternMatchers/MatchSelectorsForEither.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
using SuccincT.Functional; | ||
using SuccincT.Options; | ||
using SuccincT.PatternMatchers; | ||
using System; | ||
using System.Collections.Generic; | ||
using static SuccincT.Utilities.NRTSupport; | ||
|
||
namespace SuccincT.Unions.PatternMatchers | ||
{ | ||
internal sealed class MatchSelectorsForEither<TLeft, TRight, TResult> | ||
{ | ||
private readonly MatchFunctionSelector<TLeft, TLeft, TResult> _leftSelector; | ||
private readonly MatchFunctionSelector<TRight, TRight, TResult> _rightSelector; | ||
private Func<Either<TLeft, TRight>, TResult>? _elseFunction; | ||
|
||
internal MatchSelectorsForEither() | ||
{ | ||
_leftSelector = | ||
new MatchFunctionSelector<TLeft, TLeft, TResult>( | ||
x => throw new NoMatchException("No match action defined for either with Left value")); | ||
_rightSelector = | ||
new MatchFunctionSelector<TRight, TRight, TResult>( | ||
x => throw new NoMatchException("No match action defined for either with Right value")); | ||
} | ||
|
||
internal void RecordAction<T>(Func<T, IList<T>, bool>? withTest, | ||
Func<T, bool>? whereTest, | ||
IList<T>? withData, | ||
Func<T, TResult> action) => | ||
Selector<T>().AddTestAndAction(withTest, withData, whereTest, action); | ||
|
||
internal void RecordAction<T>(Func<T, IList<T>, bool>? withTest, | ||
Func<T, bool>? whereTest, | ||
IList<T>? withData, | ||
Func<T, Unit> action) => | ||
Selector<T>().AddTestAndAction(withTest, withData, whereTest, action.ToFuncOf<T, TResult>()); | ||
|
||
internal void RecordElseFunction(Func<Either<TLeft, TRight>, TResult> elseFunction) => | ||
_elseFunction = elseFunction; | ||
|
||
internal void RecordElseAction(Action<Either<TLeft, TRight>> elseAction) => | ||
_elseFunction = elseAction.ToUnitFunc() as Func<Either<TLeft, TRight>, TResult>; | ||
|
||
internal TResult ResultNoElse(Either<TLeft, TRight> either) => | ||
DetermineResultUsingDefaultIfRequired(either); | ||
|
||
internal TResult ResultUsingElse(Either<TLeft, TRight> either) | ||
{ | ||
var possibleResult = DetermineResult(either); | ||
return possibleResult.HasValue ? possibleResult.Value : ElseFunction(either); | ||
} | ||
|
||
internal void ExecNoElse(Either<TLeft, TRight> either) => | ||
DetermineResultUsingDefaultIfRequired(either); | ||
|
||
internal void ExecUsingElse(Either<TLeft, TRight> either) | ||
{ | ||
var possibleResult = DetermineResult(either); | ||
_ = possibleResult.HasValue ? possibleResult.Value : ElseFunction(either); | ||
} | ||
|
||
private MatchFunctionSelector<T, T, TResult> Selector<T>() | ||
=> typeof(T) switch { | ||
var t when t == typeof(TLeft) => (_leftSelector as MatchFunctionSelector<T, T, TResult>)!, | ||
_ => (_rightSelector as MatchFunctionSelector<T, T, TResult>)! | ||
}; | ||
|
||
private TResult DetermineResultUsingDefaultIfRequired(Either<TLeft, TRight> either) | ||
=> either.IsLeft | ||
? _leftSelector.DetermineResultUsingDefaultIfRequired(either.Left) | ||
: _rightSelector.DetermineResultUsingDefaultIfRequired(either.Right); | ||
|
||
|
||
private Option<TResult> DetermineResult(Either<TLeft, TRight> either) | ||
=> either.IsLeft | ||
? _leftSelector.DetermineResult(either.Left) | ||
: _rightSelector.DetermineResult(either.Right); | ||
|
||
private TResult ElseFunction(Either<TLeft, TRight> either) => _elseFunction!(either); | ||
} | ||
} |
Oops, something went wrong.