FuncSharp 9.0.3

dotnet add package FuncSharp --version 9.0.3                
NuGet\Install-Package FuncSharp -Version 9.0.3                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="FuncSharp" Version="9.0.3" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add FuncSharp --version 9.0.3                
#r "nuget: FuncSharp, 9.0.3"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install FuncSharp as a Cake Addin
#addin nuget:?package=FuncSharp&version=9.0.3

// Install FuncSharp as a Cake Tool
#tool nuget:?package=FuncSharp&version=9.0.3                

FuncSharp - Functional C#

<p align="center"> <a href="https://mews.com"> <img alt="Mews" height="100px" src="https://user-images.githubusercontent.com/435787/129971779-2c64348e-05a3-49d0-b026-91913ffd68dc.png"> </a> </p>

Build Build License NuGet Downloads NuGet Version

FuncSharp is a C# library with main purpose to introduce more advanced functional programming concepts that are currently not availabile in C# natively. As on outcome, it helps reducing boilerplate code, making code more readable and avoiding bugs thanks to stronger typing. It utilizes many concepts from other functional programming languages like Haskell or Scala, that are also applicable in C#.

Core of the library is formed by algebraic data types (ADTs), namely Product and Coproduct. Get familiar with them first and make sure you understand concepts of algebraic data modeling. Just those two types, on their own, can be pretty helpful when used in your applications. Everything else this library offers is built on top of the ADTs and is an application of ADT principles to solve some real life use-cases. You can find practical examples in the FuncSharp.Examples project.

Algebraic Data Types

There are basic types in C# like string, int, bool, DateTime or others. But how to create more types? The standard approach is to define a new class and "wrap" some of the already available types into it. That's the idiomatic way how to do that in C#, however it has some limitations when it comes to abstraction. Without reflection, you cannot easily iterate over all the properties of a class. Or create a method that accepts classes with 3 properties and whose first property is a string. That's where algebraic data types come into picture by offering alternative ways how to form types. To be specific, 2 ways:

  • Product (also known as "and type" or "tuple") represents multiple values of other types in a single type. For example financial amount can be understood as a product of decimal value and string currency code. Written algebraically decimal AND string, using FuncSharp code IProduct2<decimal, string>. That's nothing surprising and it does not differ from standard tuples in C#.
  • Coproduct (also known as "or type", "sum type" or "disjoint union") represents exactly one of multiple other types. For example an API call result can be understood as a coproduct of either successful string response or integer error code. In algebraic language string OR int, in FuncSharp Coproduct2<string, int>. An equivalent in C# would be an abstract class (Animal) with two subclasses (Cat, Dog), however it wouldn't be type-safe and it has other drawbacks.

The nice part about ADTs is that you can combine the types recursively, however deep you want. And build up very complex types using these two basic operations. There are many good posts about ADTs, you can check out the Haskell primer on algebraic data types, how ADTs are implemented in other programming languages or great explanation of coproducts and their advantages.

Product

FuncSharp provides custom product types that can replace standard Tuples which you cannot abstract over, nor enumerate their values. They come equipped with correct structural hash code, structural equality and nice ToString method for free. The final implementation of a custom product type is therefore as boilerplate-less as possible. In order to implement a custom product type, you need to inherit the Product[N] class from FuncSharp where [N] stands for arity of the product. A constructor needs to be defined and it is often good practice to define named getters on top of the standard product value getters (e.g. ProductValue1). But this is not obligatory. Custom product type representing a point in 2-deminsional space can be seen on following example:

public class Point2D : Product2<float, float>
{
    public Point2D(float x, float y)
        : base(x, y)
    {
    }

    public float X { get { return ProductValue1; } }
    public float Y { get { return ProductValue2; } }
}

You can check more extensive example, together with usage, in the Product.cs example. A direct consequence of product types is the Unit type that can be understood as a product of zero types. In the world of .NET it becomes particularly useful when abstracting over Functions and Actions which aren't compatible. Therefore there are also conversions between Actions and Functions returning the Unit value.

Coproduct

Main advantage of coproducts that FuncSharp offers, compared to standard class hierarchy, is that the usage is compile time checked. So if you decide to add/remove another type to/from coproduct, all places that use the coproduct value become identified by compiler as an error until you add/remove the case. Coproducts can be created using Coproduct.Create[Nth] function where [Nth] stands for e.g. First or Second depending on which alternative should be created. Size of the new coproduct is inferred from the type arguments. However type signatures can become pretty big when doing this, also it's good in general to name things well, so it is recommended to rather define custom coproduct types. Just inherit Coproduct[N] where [N] stands for arity (count of alternatives) and implement constructors for each alternative. A simplified example how to represent trees using coproduct type can be seen on the following snippet:

public class Tree<A> : Coproduct2<Node<A>, Leaf>
{
    public Tree(Node<A> node) : base(node) { }
    public Tree(Leaf leaf) : base(leaf) { }
}

More extensive example can be found in the Coproduct.cs file. A coproduct of zero types (a choice from no types) is also a well known type, in FuncSharp named Nothing. This type has no instance and can be used e.g. as a return type of function that always throws an exception. So behavior of the function is encoded in its type signature.

Additional Helpful Types

Option

An Option<A> is widely used functional data type known from other languages. It represents a value that may or may not be available. Great for avoiding NullReferenceExceptions and handling the two null/non-null cases. Also in C#, nullable types are somewhat different from references (in case of nullables, you have to use the Value getter). The option type nicely unifies this discrepancy. Lot of examples how to use options is in Option.cs file.

Try

In order to handle errors or exceptions, FuncSharp features Try<A, E> that represents a result of an operation that can end with either success or error. It explicitly communicates all the possible outcomes on type level, unlike exceptions where you have to read a documentation to understand how a method can end. An extensive set of examples can be found in the following files:

  • Basics - Basic concepts.
  • Exception Handling - How to turn a standard API that uses exceptions to strongly typed one, using the try type.
  • Parsing - How to safely parse unsafe incoming data.
  • General Usage - Putting it all together, a few advanced concepts.

Morphism

Simplistic implementation of finite morphisms between two types. Isomorphisms can be used as a concise representation of a bidirectional mapping that is in .NET traditionally represented as a pair of dictionaries.

DataCube

DataCubes represent sets of data indexed by a multidimensional index. E.g. a two-dimensional data cube is roughly equivalent to Dictionary<Tuple2<P1, P2>, TValue>. However data cubes are much more friendlier to work with, they provide nicer API than dictionary and offer many more advanced operations like slicing, aggregations, transformations, filtering etc.

Order

Defines partial or total order for a type. By implementing the Less operation that compares two instances of the type, you get many many useful functions based on that. Starting from finding minimum or maximum in a collection of the instances, it allows you to work with intervals bounded by the type instances. And moreover working with interval sets which essentially represent a disjoint set of intervals. You can e.g. get an interval set as a result of union of two disjoint intervals.

Generic representation of an interval and interval set may seem simple on the first sight, but becomes really handy when you consider all the cases it supports (and you'd have to implement): empty or single-value interval, any combination a bounded/unbounded interval with open/closed lower/upper bound, and finally unbounded interval. And also interval sets consisting of any combination of the aforementioned intervals. In combination with all the operations on them (Contains, Intersect, Union etc.) it becomes obvious, it's not something anybody would like to implement more than once. Or not even once. However implementing the Less operation is trivial and you get the rest for free.

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net6.0

    • No dependencies.

NuGet packages (9)

Showing the top 5 NuGet packages that depend on FuncSharp:

Package Downloads
Mews.Fiscalizations.All

All Mews Fiscalizations

Mews.Fiscalizations.Core

Core library for implementing other fiscalization libraries.

Mews.Fiscalizations.Czechia

Client for EET - Czech fiscal machines.

Mews.Fiscalizations.Spain

A package for issued invoices for spanish fiscalization. (Sii)

Mews.Fiscalizations.Germany

Client for Fiskaly - German Fiscalization.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
9.0.3 5,494 2/15/2024
9.0.2 18,286 1/4/2024
9.0.1 481 1/3/2024
9.0.0 868 12/27/2023
8.0.0 8,826 10/12/2023
8.0.0-preview.3 1,210 9/22/2023
8.0.0-preview.2 97 9/22/2023
8.0.0-preview.1 875 9/7/2023
7.0.1 2,625 8/27/2023
6.0.0 2,333 8/2/2023
4.3.1 1,886 12/15/2022
4.3.0 3,798 10/4/2022
4.2.0 127,032 5/21/2022
4.1.1 52,199 12/3/2021
4.1.0 2,358 11/26/2021
4.0.0 23,609 10/31/2021
3.0.3 9,191 10/10/2021
3.0.2 951 10/4/2021
3.0.1 81,635 4/29/2021
3.0.0 1,565 1/25/2021
2.0.1 12,104 1/12/2020
2.0.0 1,326 1/12/2020
1.7.1 45,763 7/6/2020
1.7.0 1,787 1/1/2020
1.6.5 74,665 4/23/2019
1.6.4 1,626 4/23/2019
1.6.3 1,609 4/23/2019
1.6.2 1,838 4/22/2019
1.6.1 1,665 4/22/2019
1.6.0 1,632 4/20/2019
1.5.6 2,595 3/20/2019
1.5.5 2,039 2/28/2019
1.5.4 1,733 2/19/2019
1.5.3 1,650 1/24/2019
1.5.2 2,354 1/14/2019
1.5.1 1,664 1/14/2019
1.5.0 1,694 1/14/2019
1.4.3 1,731 1/2/2019
1.4.2 1,726 1/2/2019
1.4.1 2,558 12/30/2018
1.4.0 1,637 12/20/2018
1.3.0 1,749 12/14/2018
1.2.4 1,886 11/25/2018
1.2.3 1,745 11/25/2018
1.2.2 2,503 10/25/2018
1.2.1 1,827 10/12/2018
1.2.0 1,786 10/5/2018
1.1.3 1,743 10/3/2018
1.1.2 1,771 9/27/2018
1.1.1 1,691 9/27/2018
1.1.0 1,747 9/27/2018
1.0.0 1,768 9/27/2018
0.10.1 1,845 8/16/2018
0.10.0 2,049 6/3/2018
0.9.4 2,043 5/15/2018
0.9.3 1,939 4/24/2018
0.9.2 1,822 4/24/2018
0.9.1 1,998 3/7/2018
0.9.0 1,999 2/16/2018
0.8.3 2,003 2/14/2018
0.8.2 2,011 1/31/2018
0.8.1 2,009 1/15/2018
0.8.0 1,975 1/10/2018
0.7.1 2,017 12/8/2017
0.7.0 1,981 12/7/2017
0.6.7 2,166 10/4/2017
0.6.6 2,097 9/25/2017
0.6.5 2,147 9/15/2017
0.6.4 1,979 7/3/2017
0.6.3.1 1,938 5/8/2017
0.6.3 1,974 3/6/2017
0.6.2 1,983 2/23/2017
0.6.1 1,958 1/29/2017
0.6.0 1,993 1/29/2017
0.5.1.2 2,576 9/19/2016
0.5.1.1 2,508 9/18/2016
0.5.1 2,231 8/18/2016
0.5.0.1 2,459 6/16/2016
0.5.0 2,234 3/13/2016
0.4.11.4 2,431 3/13/2016
0.4.11.3 2,327 3/11/2016
0.4.11 2,223 2/4/2016
0.4.10 2,206 1/10/2016
0.4.9 2,224 12/14/2015
0.4.8 2,224 12/14/2015
0.4.7 2,207 12/11/2015
0.4.6 2,346 12/11/2015
0.4.5 2,315 12/6/2015
0.4.4 2,264 10/28/2015
0.4.3 2,213 10/26/2015
0.4.2 2,186 10/22/2015
0.4.1 2,314 9/24/2015
0.4.0 2,264 9/11/2015
0.3.1 2,347 4/4/2015
0.3.0 2,274 4/4/2015
0.2.0 2,499 12/1/2014
0.1.0 3,437 11/9/2014

Second parameter of Option.MatchAsync is now optional.