Skip to content
David Arno edited this page Jun 27, 2016 · 34 revisions

Succinc<T>

Discriminated unions, pattern matching and partial applications for C#


Current release: v2.0.0

Release Notes

v2.0.0

Please be warned that this release includes a number of breaking changes. Please consult the documentation before installing.

This release includes:

  • A completely rewritten implementation of pattern matching (keeping the same semantics, so this shouldn't break and existing uses),
  • A new Unit type and associated methods for converting Action<T..> delegates to Func<T...,Unit> ones,
  • New Lambda, Transform, Func and Action methods to simplify the declaration and typing of lambdas.
  • A new Maybe type, which is a struct version of Option. This type is largely interchangable with Option and is provided for those that (a) prefer the semantics associated with "maybe" versus "option" and (b) those that prefer the idea of such a type being a struct (and those not able to be null.

Release notes for previous versions


Features

Discriminated Unions

Succinc<T> provides a set of union types (Union<T1, T2>, Union<T1, T2, T3> and Union<T1, T2, T3, T4>) where an instance will hold exactly one value of one of the specified types. In addition, it provides the likes of Option<T> and Maybe<T> that can have the value Some<T> or None.

Succinc<T> uses Option<T> to provide replacements for the .NET basic types' TryParse() methods and Enum.Parse(). In all cases, these are extension methods to string and they return Some<T> on a successful parse and None when the string is not a valid value for that type. No more out parameters! See the Option Parsers guide for more details.

Further Succinc<T> uses Option<T> to provide replacements for the XxxxOrDefault LINQ extension methods on IEnumerable<T>. In all cases, these new extension methods, eg TryFirst<T>() return an option with a value if a match occurred, or None if not.

Pattern Matching

Succinc<T> can pattern match values, tuples, unions etc in a way similar to F#'s pattern matching features. It uses a fluent (method chaining) syntax to achieve this. Some examples of its abilities:

public static void PrintColorName(Color color)
{
    color.Match()
         .With(Color.Red).Do(x => Console.WriteLine("Red"))
         .With(Color.Green).Do(x => Console.WriteLine("Green"))
         .With(Color.Blue).Do(x => Console.WriteLine("Blue"))
         .Exec();
}

public static string SinglePositiveOddDigitReporter(Option<int> data)
{
    return data.Match<string>()
               .Some().Of(0).Do(x => "0 isn't positive or negative")
               .Some().Where(x => x == 1 || x == 3 || x == 5 || x == 7 || x == 9).Do(x => x.ToString())
               .Some().Where(x => x > 9).Do(x => string.Format("{0} isn't 1 digit", x))
               .Some().Where(x => x < 0).Do(i => string.Format("{0} isn't positive", i))
               .Some().Do(x => string.Format("{0} isn't odd", x))
               .None().Do(() => string.Format("There was no value"))
               .Result();
}

See the Succinc<T> pattern matching guide for more details.

Partial Applications

Succinc<T> supports partial function applications. A parameter can be supplied to a multi-parameter method and a new function will be returned that takes the remaining parameters. For example:

var times = Lambda<double>((p1, p2) => p1 * p2);
var times8 = times.Apply(8);
var result = times8(9); // <- result == 72

See the Succinc<T> partial applications guide for more details.

"Implicitly" Typed Lambdas

C# doesn't support implicitly typed lambdas, meaning it's not possible to declare something like:

var times = (p1, p2) => p1 * p2;

Normally, times would have to explicitly typed:

Func<double, double, double> times = (p1, p2) => p1 * p2;

Succinc<T> offers an alternative approach, taking advantage of the fact that var can be used if the result of a method is assigned to the variable. Using the Func, Action, Transform and Lambda set of methods, the above can be expressed more simply as:

var times = Lambda<double>((p1, p2) => p1 * p2);

For functions, the Lambda methods can be used when the parameters and return type all have the same value, as above. This means the type parameter need only be specified once. Transform can be used when all the parameters are of one type and the return value, another. The Func methods are used when the parameters and/or return type are of different values. For actions, Lambda can also be used when only one type is involved and the Action methods do a similar job to the Func methods.

This is explained in detail in the Succinc<T> typed lambdas guide.

Action/Func conversions

The ToUnitFunc methods supplied by Succinc<T> can be used to cast an Action lambdas or method (from 0 to 4 parameters) to a Func delegate that returns unit, allowing void methods to be treated as functions and thus eg used in ternary oprators. In addition, Succinc<T> provides an Ignore method that can be used to explicitly ignore the result of any expression, effectively turning that expression into a void

These methods are explained in detail in the Succinc<T> Action/Func conversions guide.

Types

The following types are defined by Succinc<T>.