DCP.CoMonad
1.0.3
See the version list below for details.
dotnet add package DCP.CoMonad --version 1.0.3
NuGet\Install-Package DCP.CoMonad -Version 1.0.3
<PackageReference Include="DCP.CoMonad" Version="1.0.3" />
paket add DCP.CoMonad --version 1.0.3
#r "nuget: DCP.CoMonad, 1.0.3"
// Install DCP.CoMonad as a Cake Addin #addin nuget:?package=DCP.CoMonad&version=1.0.3 // Install DCP.CoMonad as a Cake Tool #tool nuget:?package=DCP.CoMonad&version=1.0.3
DCP.CoMonad
Minimal C# Functional Extensions for the 'Happy Path'
Index
Functional
What is functional programming anyway?
Style
A style that treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data.
Because it is just a style there is no requirement to use a 'functional language', although these may have defaults to immutability and even compiler restrictions that simplify or enforce the style.
The terms 'Pure', 'deterministic', 'referential transparency' are fancy descriptors for this style.
First Class Functions and Higher-order functions
An ability to pass and recieve functions as parameters.
.Net and indeed most languages possess this ability. Func<T..n> and delegates represent this ability in .Net
The important thing to note is that .Net (C# in particular) is fully capable of functional programming style and technique.
Introduction
Inspired by Scott Wlaschin and and railway oriented program design principles, with the requirement to eradicate exceptions from code paths we focus on using functional mechanisms.
The latest features of C sharp enable us to adopt new paradigms based on functional monadic design.
Eradicate Exceptions
Using the Result<T> class to represent the discriminated union of either result or error allows us to adopt railway oriented programming, chaining function calls and reducing code paths to a single railway track.
Result<T> implements Map, Bind, MapAsync, BindAsync
With these few methods we can transform code to more functional happy paths.
eg Checked Math simple example
Result<int> Divide(int a,int b)=>b==0?RezErr.DivideByZero:Result.Ok(a/b);
//C# will not overflow unless using checked math
Result<int> Add(int a,int b)=>b==try{return Result.Ok(checked(a+b));catch(System.OverflowException){return RezErr.Overflow;}
Result<int> AddDivide(int a,int b,int c)=> Add(a,b).Bind(r=>Divide(r,c));
The key thing to recognise is that this code will not throw errors yet will performed checked maths.
Indeed the primary requirement is that all methods that return Result<T> will not throw errors.
Once this requirement is in place we can remove all error handling of exceptions when calling these methods and simply handle the end case result no matter how long the function call chain.
New World
Transitioning to returning Result<T> from functions is simple to implement and peppers your code with ability to chain function calls using the map and bind.
Once using this mechanism with chained function calls your ability to reason about code and follow the code path is enhanced.
Scott Wlaschin describes this as moving into a new parallel world which is a nice concept.
What! No Option or Maybe
This library contains no option or maybe. This is a design decision to transition to use of nullable reference types.
Nullable reference types in effect make the option or maybe types irrelevant. Of course this requires implementing nullable reference types correctly
Monads
A Monad is 'a box of something'.
ROP Development ideas
Railway oriented programming
Functional Design Patterns - Scott Wlaschin The original.
Railway-Oriented Programming in C# - Marcus Denny
The Power of Composition - Scott Wlaschin
Vladimir Khomrikov on Pluralsight
Map
Select in C#
Bind
SelectMany in C#
Tee
Action and return in C#
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 is compatible. 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.1 is compatible. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 is compatible. |
.NET Framework | net45 is compatible. net451 was computed. net452 was computed. net46 was computed. net461 is compatible. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 is compatible. net48 is compatible. net481 was computed. |
-
.NETCoreApp 2.1
- Microsoft.Bcl.AsyncInterfaces (>= 1.1.1)
- System.Linq.Async (>= 4.1.1)
- System.ValueTuple (>= 4.5.0)
-
.NETCoreApp 3.1
- System.Linq.Async (>= 4.1.1)
-
.NETFramework 4.5
- AsyncEnumerator (>= 4.0.2)
- System.Runtime.CompilerServices.Unsafe (>= 4.7.1)
- System.Threading.Tasks.Extensions (>= 4.5.4)
- System.ValueTuple (>= 4.5.0)
-
.NETFramework 4.6.1
- Microsoft.Bcl.AsyncInterfaces (>= 1.1.1)
- System.Linq.Async (>= 4.1.1)
- System.Threading.Tasks.Extensions (>= 4.5.4)
- System.ValueTuple (>= 4.5.0)
-
.NETFramework 4.7.2
- Microsoft.Bcl.AsyncInterfaces (>= 1.1.1)
- System.Linq.Async (>= 4.1.1)
- System.Threading.Tasks.Extensions (>= 4.5.4)
-
.NETFramework 4.8
- Microsoft.Bcl.AsyncInterfaces (>= 1.1.1)
- System.Linq.Async (>= 4.1.1)
-
net5.0
- System.Linq.Async (>= 4.1.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.