dotMaybe 0.3.0
See the version list below for details.
dotnet add package dotMaybe --version 0.3.0
NuGet\Install-Package dotMaybe -Version 0.3.0
<PackageReference Include="dotMaybe" Version="0.3.0" />
paket add dotMaybe --version 0.3.0
#r "nuget: dotMaybe, 0.3.0"
// Install dotMaybe as a Cake Addin #addin nuget:?package=dotMaybe&version=0.3.0 // Install dotMaybe as a Cake Tool #tool nuget:?package=dotMaybe&version=0.3.0
dotMaybe - The Maybe Monad for .NET
dotMaybe is a lightweight, intuitive implementation of the Maybe monad for .NET. It simplifies working with optional values, eliminating null reference exceptions and promoting a more functional, declarative programming style.
Give it a star ⭐!
If you find this project valuable, please consider giving it a star! Your support helps others discover this work and encourages further development.
Maybe<T>
API Documentation
Overview
The Maybe<T>
monad represents a value that may or may not exist, encapsulating the concept of optional data. It provides methods to safely handle, transform, and operate on potentially absent values, offering a robust alternative to null references in both synchronous and asynchronous contexts.
Properties
IsSome
public bool IsSome { get; }
Gets a value indicating whether the maybe contains a value.
Example:
var maybe = Some.With(42);
if (maybe.IsSome)
{
Console.WriteLine("Contains value!");
}
IsNone
public bool IsNone { get; }
Gets a value indicating whether the maybe is empty.
Example:
var maybe = None.OfType<int>();
if (maybe.IsNone)
{
Console.WriteLine("Is empty!");
}
Methods
Match
public TResult Match<TResult>(Func<TResult> none, Func<T, TResult> some)
Executes one of two provided functions based on whether the Maybe<T>
contains a value or not.
Example:
var maybe = Some.With(42);
var message = maybe.Match(
() => "Is empty",
value => "Value: " + value);
Console.WriteLine(message);
MatchAsync
public async Task<TResult> MatchAsync<TResult>(Func<Task<TResult>> none, Func<T, Task<TResult>> some)
Asynchronously executes one of two provided functions based on whether the Maybe<T>
contains a value or not.
Example:
var maybe = Some.With(42);
var message = await maybe.MatchAsync(
async () => await Task.FromResult("Is empty"),
async value => await Task.FromResult("Value: " + value));
Console.WriteLine(message);
MatchAsync
public async Task<TResult> MatchAsync<TResult>(Func<TResult> none, Func<T, Task<TResult>> some)
Asynchronously executes one of two provided functions based on whether the Maybe<T>
contains a value or not, with a synchronous fallback for the None case.
Example:
var maybe = Some.With(42);
var message = await maybe.MatchAsync(
() => "Is empty",
async value => await Task.FromResult("Value: " + value));
Console.WriteLine(message);
Map
public Maybe<TResult> Map<TResult>(Func<T, TResult> map)
Transforms the value inside a Maybe<T> using the provided mapping function, if a value exists.
Example:
var maybe = Some.With(42);
var mappedMaybe = maybe.Map(value => value.ToString());
Console.WriteLine(mappedMaybe.Match(
() => "Empty",
value => value));
MapAsync
public Task<Maybe<TResult>> MapAsync<TResult>(Func<T, Task<TResult>> map)
Asynchronously transforms the value inside a Maybe<T> using the provided mapping function, if a value exists.
Example:
var maybe = Some.With(42);
var mappedMaybe = await maybe.MapAsync(async value => await Task.FromResult(value.ToString()));
Console.WriteLine(mappedMaybe.Match(
() => "Empty",
value => value));
Bind
public Maybe<TResult> Bind<TResult>(Func<T, Maybe<TResult>> bind)
Chains Maybe operations by applying a function that returns a new Maybe, allowing for composition of operations that might fail.
Example:
var maybe = Some.With(42);
var boundMaybe = maybe.Bind(value => Some.With(value.ToString()));
Console.WriteLine(boundMaybe.Match(
() => "Empty",
value => value));
BindAsync
public Task<Maybe<TResult>> BindAsync<TResult>(Func<T, Task<Maybe<TResult>>> bind)
Chains Maybe operations by asynchronously applying a function that returns a new Maybe, allowing for composition of operations that might fail.
Example:
var maybe = Some.With(42);
var boundMaybe = await maybe.BindAsync(async value => await Task.FromResult(Some.With(value.ToString())));
Console.WriteLine(boundMaybe.Match(
() => "Empty",
value => value));
Fold
public TState Fold<TState>(TState state, Func<TState, T, TState> folder)
Reduces the Maybe<T>
to a single value by applying a folder function if a value exists, otherwise returns the initial state.
Example:
var maybe = None.OfType<int>();
var foldedResult = maybe.Fold(0, (acc, value) => acc + value);
Console.WriteLine(foldedResult); // Outputs: 0
var maybe = Some.With(42);
var foldedResult = maybe.Fold(0, (acc, value) => acc + value);
Console.WriteLine(foldedResult); // Outputs: 42
var maybe = Some.With(42);
var foldedResult = maybe.Fold(10, (acc, value) => acc + value);
Console.WriteLine(foldedResult); // Outputs: 52
Filter
public public Maybe<T> Filter(Predicate<T> predicate)
Applies a predicate to the value in Maybe<T>, returning None if the predicate fails or the value doesn't exist.
Example:
var maybe = Some.With(42);
var filteredMaybe = maybe.Filter(value => value < 50);
Console.WriteLine(filteredMaybe.Match(
() => "Empty",
value => "Value: " + value)); // Outputs: Value: 42
var maybe = Some.With(52);
var filteredMaybe = maybe.Filter(value => value < 50);
Console.WriteLine(filteredMaybe.Match(
() => "Empty",
value => "Value: " + value)); // Outputs: Empty
var maybe = None.OfType<int>();
var filteredMaybe = maybe.Filter(value => value < 50);
Console.WriteLine(filteredMaybe.Match(
() => "Empty",
value => "Value: " + value)); // Outputs: Empty
OrDefault
public T OrDefault(T defaultValue)
Returns the value if it exists, otherwise returns the specified default value.
Example:
var maybe = None.OfType<int>();
var value = maybe.OrDefault(100);
Console.WriteLine(value); // Outputs: 100
var result = Some.With(42);
var value = result.OrDefault(100);
Console.WriteLine(value); // Outputs: 42
OrDefault
public T OrDefault(Func<T> defaultFactory)
Returns the value if it exists, otherwise invokes the provided factory function to create a default value.
Example:
var maybe = None.OfType<int>();
var value = maybe.OrDefault(() => 100);
Console.WriteLine(value); // Outputs: 100
var result = Some.With(42);
var value = result.OrDefault(() => 100);
Console.WriteLine(value); // Outputs: 42
Static Methods
Implicit conversion
public static implicit operator Maybe<T>(T? value)
Create a Maybe instance containing the specified value. Or None if the value is null.
Example:
Maybe<int> maybe = 42;
Console.WriteLine(maybe.IsSome); // Outputs: True
int? x = null;
Maybe<int> maybe = x;
Console.WriteLine(maybe.IsNone); // Outputs: True
Flatten
public static Maybe<T> Flatten<T>(this Maybe<Maybe<T>> nested)
Flattens a nested Maybe, reducing Maybe<Maybe<T>> to Maybe<T>.
Example:
Maybe<Maybe<int>> nested = 42.ToMaybe().ToMaybe();
Maybe<int> flattened = nested.Flatten();
T extensions
ToMaybe
public static Maybe<T> ToMaybe<T>(this T value)
Example:
Maybe<string> maybe = "Hello, World!".ToMaybe();
Console.WriteLine(maybe.IsSome); // Outputs: True
string? x = null;
Maybe<string> maybe = x.ToMaybe();
Console.WriteLine(maybe.IsNone); // Outputs: True
Convert a value to a Maybe instance.
ToMaybe
public static Maybe<T> ToMaybe<T>(this T? value) where T : struct
Convert a nullable value type to a Maybe instance.
Example:
Maybe<int> maybe = 42.ToMaybe();
Console.WriteLine(maybe.IsSome); // Outputs: True
int? x = null;
Maybe<int> maybe = x.ToMaybe();
Console.WriteLine(maybe.IsNone); // Outputs: True
IEnumerable<T> extensions
FirstOrNone
public static Maybe<T> FirstOrNone<T>(this IEnumerable<T> source)
Returns the first element of a sequence as a Maybe, or an empty Maybe if the sequence contains no elements.
Example:
IEnumerable<int> collection = [42];
Maybe<int> maybe = collection.FirstOrNone();
Console.WriteLine(maybe.IsSome); // Outputs: True
IEnumerable<int> collection = [];
Maybe<int> maybe = collection.FirstOrNone();
Console.WriteLine(maybe.IsNone); // Outputs: True
FirstOrNone
public static Maybe<T> FirstOrNone<T>(this IEnumerable<T> source, Func<T, bool> predicate)
Returns the first element of a sequence that satisfies a specified condition as a Maybe, or an empty Maybe if no such element is found.
Example:
IEnumerable<int> collection = [42];
Maybe<int> maybe = collection.FirstOrNone(v => v > 40);
Console.WriteLine(maybe.IsSome); // Outputs: True
IEnumerable<int> collection = [42];
Maybe<int> maybe = collection.FirstOrNone(v => v < 40);
Console.WriteLine(maybe.IsNone); // Outputs: True
IEnumerable<int> collection = [];
Maybe<int> maybe = collection.FirstOrNone(v => v > 0);
Console.WriteLine(maybe.IsNone); // Outputs: True
Static Methods on Static Class Maybe
Map2
public static Maybe<TResult> Map2<T1, T2, TResult>(
Maybe<T1> maybe1,
Maybe<T2> maybe2,
Func<T1, T2, TResult> map)
Combines two Maybe instances using a mapping function.
Example:
Maybe<string> result = Maybe.Map3(
Some.With(1),
Some.With("Hello there!"),
(v1, v2) => $"{v1}: {v3}");
string message = result.Match(() => "EMPTY", v => v);
Console.WriteLine(message); // outputs: 1: Hello there!
Maybe<string> result = Maybe.Map2(
None.OfType<int>(),
Some.With("Hello there!"),
(v1, v2) => $"{v1}: {v3}");
string message = result.Match(() => "EMPTY", v => v);
Console.WriteLine(message); // outputs: EMPTY
Maybe<string> result = Maybe.Map2(
Some.With(1),
None.OfType<string>(),
(v1, v2) => $"{v1}: {v3}");
string message = result.Match(() => "EMPTY", v => v);
Console.WriteLine(message); // outputs: EMPTY
Map3
public static Maybe<TResult> Map3<T1, T2, T3, TResult>(
Maybe<T1> maybe1,
Maybe<T2> maybe2,
Maybe<T3> maybe3,
Func<T1, T2, T3, TResult> map)
Combines three Maybe instances using a mapping function.
Example:
Maybe<string> result = Maybe.Map3(
Some.With(1),
Some.With("abcd"),
Some.With("Hello there!"),
(v1, v2, v3) => $"{v1} ({v2}): {v3}");
string message = result.Match(() => "EMPTY", v => v);
Console.WriteLine(message); // outputs: 1 (abcd): Hello there!
Maybe<string> result = Maybe.Map3(
None.OfType<int>(),
Some.With("abcd"),
Some.With("Hello there!"),
(v1, v2, v3) => $"{v1} ({v2}): {v3}");
string message = result.Match(() => "EMPTY", v => v);
Console.WriteLine(message); // outputs: EMPTY
Maybe<string> result = Maybe.Map3(
Some.With(1),
None.OfType<string>(),
Some.With("Hello there!"),
(v1, v2, v3) => $"{v1} ({v2}): {v3}");
string message = result.Match(() => "EMPTY", v => v);
Console.WriteLine(message); // outputs: EMPTY
Maybe<string> result = Maybe.Map3(
Some.With(1),
Some.With("abcd"),
None.OfType<string>(),
(v1, v2, v3) => $"{v1} ({v2}): {v3}");
string message = result.Match(() => "EMPTY", v => v);
Console.WriteLine(message); // outputs: EMPTY
Query syntax
Select
public Maybe<TResult> Select<TResult>(Func<T, TResult> selector)
Transforms the value inside a Maybe<T> using the provided mapping function, if a value exists.
Example:
Maybe<string> mappedMaybe =
from x in Some.With(42)
select x.ToString();
Console.WriteLine(mappedMaybe.Match(
() => "Empty",
value => value)); // Outputs: 42
Maybe<string> mappedMaybe =
from x in None.OfType<int>
select x.ToString();
Console.WriteLine(mappedMaybe.Match(
() => "Empty",
value => value)); // Outputs: Empty
SelectMany
public Maybe<TResult> SelectMany<TIntermediate, TResult>(
Func<T, Maybe<TIntermediate>> intermediateSelector,
Func<T, TIntermediate, TResult> resultSelector)
Projects the value of a Maybe into a new Maybe, then flattens the result into a single Maybe.
Example:
Maybe<string> boundMaybe =
from v1 in Some.With(1)
from v2 in Some.With("abcd")
from v3 in Some.With("Hello there!")
select $"{v1} ({v2}): {v3}";
Console.WriteLine(boundMaybe.Match(
() => "Empty",
value => value)); // Outputs: 1 (abcd): Hello there!
Maybe<string> boundMaybe =
from v1 in None.OfType<int>()
from v2 in Some.With("abcd")
from v3 in Some.With("Hello there!")
select $"{v1} ({v2}): {v3}";
Console.WriteLine(boundMaybe.Match(
() => "Empty",
value => value)); // Outputs: Empty
Maybe<string> boundMaybe =
from v1 in Some.With(1)
from v2 in Some.With("abcd")
from v3 in None.OfType<string>()
select $"{v1} ({v2}): {v3}";
Console.WriteLine(boundMaybe.Match(
() => "Empty",
value => value)); // Outputs: Empty
Maybe<string> boundMaybe =
from v1 in Some.With(1)
from v2 in None.OfType<string>()
from v3 in Some.With("Hello there!")
select $"{v1} ({v2}): {v3}";
Console.WriteLine(boundMaybe.Match(
() => "Empty",
value => value)); // Outputs: Empty
Where
public Maybe<T> Where(Predicate<T> predicate)
Applies a predicate to the value in Maybe<T>, returning None if the predicate fails or the value doesn't exist.
Example:
Maybe<int> filteredMaybe =
from x in Some.With(42)
where x > 40
select x;
Console.WriteLine(filteredMaybe.Match(
() => "Empty",
value => value.ToString())); // Outputs: 42
Maybe<int> filteredMaybe =
from x in Some.With(42)
where x < 40
select x; // None
Console.WriteLine(filteredMaybe.Match(
() => "Empty",
value => value.ToString())); // Outputs: Empty
Maybe<int> filteredMaybe =
from x in None.OfType<int>()
where x < 40
select x; // None
Console.WriteLine(filteredMaybe.Match(
() => "Empty",
value => value.ToString())); // Outputs: Empty
Contribution
If you would like to contribute to this project, check out CONTRIBUTING file.
License
This project is licensed under the terms of the MIT license.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
- Add FirstOrNone extension method for IEnumerable of T
- Add FirstOrNone with predicate extension method for IEnumerable of T
- Add MapAsync method
- Add MapAsync methods for Task of Maybe of T
- Add ConfigureAwait for async calls
- Add BindAsync method
- Add BindAsync method for Task of Maybe of T
- Func of T and bool to Predicate of T where possible