micro-elements - MicroElements.Functional 1.0.0-beta.4
C# implementation of functional concepts: Maybe (Option), Either (Result), Try, Memoize
PM> Install-Package MicroElements.Functional -Version 1.0.0-beta.4 -Source https://www.myget.org/F/micro-elements/api/v3/index.json
> nuget.exe install MicroElements.Functional -Version 1.0.0-beta.4 -Source https://www.myget.org/F/micro-elements/api/v3/index.json
> dotnet add package MicroElements.Functional --version 1.0.0-beta.4 --source https://www.myget.org/F/micro-elements/api/v3/index.json
source https://www.myget.org/F/micro-elements/api/v3/index.json
nuget MicroElements.Functional ~> 1.0.0-beta.4
Copy to clipboard
> choco install MicroElements.Functional --version 1.0.0-beta.4 --source https://www.myget.org/F/micro-elements/api/v2
Import-Module PowerShellGet
Register-PSRepository -Name "micro-elements" -SourceLocation "https://www.myget.org/F/micro-elements/api/v2"
Install-Module -Name "MicroElements.Functional" -RequiredVersion "1.0.0-beta.4" -Repository "micro-elements" -AllowPreRelease
Copy to clipboard
MicroElements.Functional
Small subset of functional methodology in C#
Statuses
Summary
MicroElements.Functional is another one try to use functional paradigm in C#. Functional approach can lead error elimination and more explicit logic.
Why I wrote one more lib? I tryed to use many monadic libs: louthy/language-ext, nlkl/Optional, la-yumba/functional-csharp-code, vkhorikov/CSharpFunctionalExtensions but there was some limitations or discomfort. LanguageExt is full featured but but it is very fat, Optional is very verbose and has only Option and Option with error, functional-csharp-code is cool but is a sort of book examples, all libs had not use new performance features of C#. And I decided to replace all functional libs with new... %)
Main features
- Option
- Result<A, Error> (Either)
- Result<A, Error, Message>
- ValueObject
- Memoise
- Try monad
- Message and MessageList
- Extensions for parsing, collections
Installation
Package Reference:
dotnet add package MicroElements.Functional
Build
Windows: Run build.ps1
Linux: Run build.sh
License
This project is licensed under the MIT license. See the LICENSE file for more info.
Usage
Option is value that can be in one of two states: Some(a) or None.
Creating Optional values
// Create some option.
var someInt = Some(123);
// Implicit convert to option.
Option<string> name = "Bill";
// None.
Option<string> noneString = None;
Option<int> noneInt = None;
// Extension method to create some value.
var someString = "Sample".ToSome();
Match
// Match returns (123+1).
int plusOne = someInt.Match(i => i + 1, () => 0);
Console.WriteLine($"plusOne: {plusOne}");
// Match returns 0.
int nonePlusOne = noneInt.Match(i => i + 1, () => 0);
Console.WriteLine($"nonePlusOne: {nonePlusOne}");
ValueObject
ValueObject is concept from DDD. see: https://martinfowler.com/bliki/ValueObject.html You need two main principle to implement ValueObject: Structural Equality and Immutability.
To implement ValueObject you need:
- implement Object.Equals
- implement Object.GetHashCode
- implement Equality operator
- implement Inequality operator
- implement IEquatable interface (optional)
- implement IComparable interface (optional)
Or you can just inherit your class from MicroElements.Functional.ValueObject and override GetEqualityComponents method.
MicroElements.Functional.ValueObject implements all routine for you. see Example.
Example
/// <summary>
/// Address for delivery.
/// </summary>
[ImmutableObject(true)]
public class Address : ValueObject
{
public string Country { get; }
public string City { get; }
public string State { get; }
public string ZipCode { get; }
public string StreetLine1 { get; }
public string StreetLine2 { get; }
public string FullName { get; }
public string PhoneNumber { get; }
public Address(string country, string city, string state, string zipCode, string streetLine1, string streetLine2, string fullName, string phoneNumber)
{
//TODO: Domain checks
Country = country;
City = city;
State = state;
ZipCode = zipCode;
StreetLine1 = streetLine1;
StreetLine2 = streetLine2;
FullName = fullName;
PhoneNumber = phoneNumber;
}
/// <inheritdoc />
public override IEnumerable<object> GetEqualityComponents()
{
yield return Country;
yield return City;
yield return State;
yield return ZipCode;
yield return StreetLine1;
yield return StreetLine2;
yield return FullName;
yield return PhoneNumber;
}
}
Option
TODO
Either
TODO
Result
TODO
Design Notes
- Most of types are structs so they can not be null
- Don't use monadic values for persistence because structs have default constructors and can be in uninitialized state
- Don't use monadic values in other data structures
- Main monad type is A, result type is B or Res
Monad checklist
- Readonly struct
- Internal constructors, all factory checks in prelude
- Monadic methods: Match, Map, Bind(FlatMap), Filter
- inputs should be not null
- result types named Res
- LINQ operations: AsEnumerable, Select(Map), Where(Filter), SelectMany
- Equality methods
- Implicit conversions
- Intermonad conversions
- Uninitialized checks or bottom state?
- Check Monad laws
- Async interoparability or async version
Monadic operations
- B Match(Func<A, B> map);
- Monad<B> Map(Func<A, B> map);
- Monad<B> Select(Func<A, B> select);
- Monad<B> Bind(Func<A, Monad<B>> bind)
- Monad<C> SelectMany<B, C>(
Func<A, Monad<B>> bind,
Func<A, B, C> project)
$# 1.0.0-beta.3
- Breaking: netstandard2.1
- Breaking: Nullable flag enabled for project
- Some extensions methods annotated with nullable notation
- Added TypeExtensions.GetDefaultValue
- Added minimal optimization for structs (readonly, in modifiers)
- Message.WithProperty fixed. Now replaces only property, not deleting existing properties
0.17.0
- Message marked as serializable
- Message: all temporary context and caches moved to MessageContext that marked as NonSerialized
- Message: Fixed With methods (default property add mode is merge now)
- Message: some optimizations
- Removed memoize in ValueObject
- Memoize extensions fixed (recursion)
0.16.0
- FirstOrNone fix for value types.
0.16.0-rc.1
- MessageTemplate
- Many extensions
0.15.0
- Added MatchUnsafe for Result types that can return null result.
- Changes: GetValueOrDefault now can return null result.
Full release notes can be found at: https://github.com/micro-elements/MicroElements.Functional.git/blob/master/CHANGELOG.md
- .NETStandard 2.1: 2.1.0.0
OwnersAlexey Petryashev |
Authorsmicro-elements |
Project URLhttps://github.com/micro-elements/MicroElements.Functional |
LicenseMIT |
Tagsmonads functional Maybe Option Either Result Try Memoize MicroElements |
Info2692 total downloads |
| 66 downloads for version 1.0.0-beta.4 |
| Download (88.46 KB) |
| Found on the current feed only |
Package history
| Version | Size | Last updated | Downloads | Mirrored? | |||
|---|---|---|---|---|---|---|---|
|
1.10.0 | 118.53 KB | Wed, 02 Dec 2020 18:18:32 GMT | 78 |
|
||
|
1.9.0 | 118.46 KB | Wed, 02 Dec 2020 12:10:57 GMT | 76 |
|
||
|
1.8.0 | 117.88 KB | Tue, 01 Dec 2020 22:39:12 GMT | 72 |
|
||
|
1.7.0 | 116.42 KB | Sun, 29 Nov 2020 16:22:49 GMT | 68 |
|
||
|
1.6.0 | 100.18 KB | Thu, 19 Nov 2020 13:49:59 GMT | 85 |
|
||
|
1.5.0 | 99.58 KB | Sun, 15 Nov 2020 20:36:50 GMT | 73 |
|
||
|
1.4.0 | 98.57 KB | Wed, 11 Nov 2020 12:25:04 GMT | 67 |
|
||
|
1.3.0 | 95.3 KB | Tue, 27 Oct 2020 08:06:30 GMT | 66 |
|
||
|
1.2.0 | 89 KB | Tue, 20 Oct 2020 10:57:43 GMT | 69 |
|
||
|
1.1.0 | 88.72 KB | Mon, 19 Oct 2020 19:39:49 GMT | 81 |
|
||
|
1.0.0 | 88.43 KB | Sun, 11 Oct 2020 14:41:56 GMT | 70 |
|
||
|
1.0.0-beta.4 | 88.46 KB | Sun, 11 Oct 2020 14:41:48 GMT | 66 |
|
||
|
1.0.0-beta.3 | 84.33 KB | Fri, 17 Jul 2020 12:19:26 GMT | 64 |
|
||
|
1.0.0-beta.2 | 84.28 KB | Mon, 06 Jul 2020 14:28:22 GMT | 82 |
|
||
|
1.0.0-beta.1 | 84.22 KB | Mon, 06 Jul 2020 13:39:36 GMT | 66 |
|
||
|
0.17.0 | 85.03 KB | Tue, 05 May 2020 18:45:06 GMT | 78 |
|
||
|
0.16.0 | 84.92 KB | Mon, 24 Feb 2020 17:33:21 GMT | 76 |
|
||
|
0.16.0-rc.4 | 75.57 KB | Tue, 18 Feb 2020 16:13:09 GMT | 76 |
|
||
|
0.16.0-rc.3 | 75.51 KB | Tue, 18 Feb 2020 08:29:39 GMT | 69 |
|
||
|
0.16.0-rc.2 | 75.45 KB | Thu, 13 Feb 2020 19:54:06 GMT | 83 |
|
||
|
0.16.0-rc.1 | 75.5 KB | Sat, 19 Oct 2019 12:54:02 GMT | 65 |
|
||
|
0.15.0 | 65.86 KB | Tue, 30 Apr 2019 14:15:20 GMT | 68 |
|
||
|
0.14.0 | 65.67 KB | Tue, 23 Apr 2019 20:53:56 GMT | 80 |
|
||
|
0.13.1 | 64.57 KB | Sun, 14 Apr 2019 20:49:16 GMT | 74 |
|
||
|
0.13.0 | 64.56 KB | Tue, 09 Apr 2019 13:27:03 GMT | 64 |
|
||
|
0.12.0 | 63.31 KB | Thu, 14 Mar 2019 15:58:06 GMT | 77 |
|
||
|
0.11.0 | 62.19 KB | Wed, 13 Mar 2019 13:48:49 GMT | 80 |
|
||
|
0.10.0 | 57.56 KB | Fri, 01 Mar 2019 20:48:26 GMT | 71 |
|
||
|
0.9.0 | 57 KB | Wed, 27 Feb 2019 13:35:13 GMT | 74 |
|
||
|
0.8.0 | 55.96 KB | Sat, 23 Feb 2019 21:20:16 GMT | 71 |
|
||
|
0.7.0 | 50.6 KB | Tue, 12 Feb 2019 21:35:43 GMT | 75 |
|
||
|
0.6.0 | 47.82 KB | Sun, 10 Feb 2019 20:53:48 GMT | 77 |
|
||
|
0.5.0 | 41.36 KB | Sun, 03 Feb 2019 22:31:15 GMT | 70 |
|
||
|
0.4.0 | 31.94 KB | Sun, 27 Jan 2019 20:55:59 GMT | 63 |
|
||
|
0.3.0 | 27.47 KB | Wed, 23 Jan 2019 21:59:04 GMT | 67 |
|
||
|
0.2.0 | 18.81 KB | Tue, 15 Jan 2019 21:31:54 GMT | 74 |
|
||
|
0.1.0 | 18.72 KB | Tue, 15 Jan 2019 20:39:36 GMT | 77 |
|