Support for C# pattern-matching
Language-ext was created before the C# pattern-matching feature existed. The default way to match within lang-ext is to use the Match(...)
methods provided for most types.
There have been requests for the struct
types to become reference-types so sub-types can represent the cases of types like Option<A>
, Either<L, R>
, etc. I don't think this is the best way forward for a number of reasons that I won't go in to here, but it would obviously be good to support the C# in-built pattern-matching.
So, now most types have a Case
property, or in the case of delegate
types like Try<A>
, or in-built BCL types like Task<T>
: a Case()
extension method.
For example, this is how to match on an Option<int>
:
var option = Some(123);
var result = option.Case switch
{
SomeCase<int>(var x) => x,
_ => 0 // None
};
Next we can try matching on an Either<string, int>
:
var either = Right<string, int>(123);
var result = either.Case switch
{
RightCase<string, int>(var r) => r,
LeftCase<string, int>(var _) => 0,
_ => 0 // Bottom
};
This is where some of the issues of C#'s pattern-matching show up, they can get quite verbose compared to calling the Match
method.
For async
types you simply have to await
the Case
:
var either = RightAsync<string, int>(123);
var result = await either.Case switch
{
RightCase<string, int>(var r) => r,
LeftCase<string, int>(var _) => 0,
_ => 0 // Bottom
};
The delegate types need to use Case()
rather than Case
:
var tryOption = TryOption<int>(123);
var result = tryOption.Case() switch
{
SuccCase<int>(var r) => r,
FailCase<int>(var _) => 0,
_ => 0 // None
};
All collection types support Case
also, they all work with the same matching system and so the cases are always the same for all collection types:
static int Sum(Seq<int> seq) =>
seq.Case switch
{
HeadCase<int>(var x) => x,
HeadTailCase<int>(var x, var xs) => x + Sum(xs),
_ => 0 // Empty
};