Skip to content

PatternMatchingValueOrError

David Arno edited this page Feb 12, 2018 · 4 revisions

Pattern Matching

Succinc<T> pattern matching guide: Options


Introduction

This pattern matching guide is split into the following sections:

A ValueOrError can contain some value string, or some error string. Pattern matching on a ValueOrError instance therefore consists of matching values, via Value() and matching errors, via Error().

Syntax

The generalised syntax for value/error patterns can be expressed using BNF-like syntax. As with all Succinc<T> pattern matching cases, there are two types of match. Firstly, matching and returning a value:

result = {option}.Match<{result type}>()
                 [ValueExpression | ErrorExpression ]...
                 [ElseExpression]
                 .Result();

ValueExpression ==>
    .Value().Do({value} => {result type expression}) |
    .Value().Do({result type expression}) |
    .Value() [WithExpression|WhereExpression]...

ErrorExpression ==>
    .Value().Do({value} => {result type expression}) |
    .Value().Do({result type expression}) |
    .Value() [WithExpression|WhereExpression]...

WithExpression ==> 
    .With({value})[.Or({value})]... .Do({value} => {result type expression}) |
    .With({value})[.Or({value})]... .Do({result type expression})

WhereExpression ==>
    .Where({item} => {boolean expression}).Do({value} => {result type expression}) |
    .Where({item} => {boolean expression}).Do({result type expression})

ElseExpression ==>
    .Else({option} => {result type expression}) |
    .Else({result type expression})

And the alternative is a match that invokes a void expression (ie, an Action<{item type}>):

{option}.Match()
        [ValueExpression | ErrorExpression ]...
        [ElseExpression]
        .Exec();

SomeExpression ==>
    .Value().Do({value} => {action on value}) |
    .Value() [WithExpression|WhereExpression]...

ErrorExpression ==>
    .Error().Do({value} => {action on value}) |
    .Error() [WithExpression|WhereExpression]...

WithExpression ==> 
    .With({value})[.Or({value})]... .Do({value} => {action on value})

WhereExpression ==>
    .Where({item} => {boolean expression}).Do({value} => {action on value})

ElseExpression ==>
    .Else({option} => {action on option}) |
    .IgnoreElse()

To explain the above syntax:

  • {} denotes a non-literal, eg {void expression} could be the empty expression, {}, or something like Console.WriteLine("hello").
  • Items in [] are optional.
  • | is or, ie [x|y] reads as "an optional x or y".
  • ... after [x] means 0 or more occurrences of x.
  • ==> is a sub-rule, which defines the expression on the left of this symbol.

Basic Usage

The most basic form is matching on there being a value or an error:

public static bool ContainsValue(ValueOrError data)
{
    return data.Match()
               .Value().Do(x => true)
               .Error().Do(x => false)
               .Result();
}

public static void PrintValueOrError(ValueOrError data)
{
    data.Match()
        .Value().Do(Console.WriteLine)
        .Error().Do(Console.WriteLine)
        .Exec();
}

In both examples above, we have used both Value() and Error(), but we could optionally use Else():

public static bool ContainsValue(ValueOrError data)
{
    return data.Match()
               .Value().Do(x => true)
               .Else(x => false)
               .Result();
}

public static void PrintValueOrError(ValueOrError data)
{
    data.Match()
        .Value().Do(Console.WriteLine)
        .Else(Console.WriteLine)
        .Exec();
}

Else() or IgnoreElse() is invoked if there is no match from any specified Value() or Error() expressions.

One further change can be made to the functional example. We are supplying a parameter, x, which isn't then used. In this case, we can dispense with the lambda and just specify the return value:

public static bool ContainsValue(ValueOrError data)
{
    return data.Match()
               .Value().Do(true)
               .Else(false)
               .Result();
}

Matching Individual Values and Errors

The previous examples just matched any value or error. We might want to match specific values and errors though. We have two choices here: using Or() and Where().

To demonstrate Firstly, using Or we could write a method to print whether the value is 1, 2 or 3, and simply report an error if it has one:

public static void OneToThreeReporter(ValueOrError data)
{
    data.Match()
        .Value().Of("1").Or("2").Or("3").Do(Console.WriteLine)
        .Value().Do(v => Console.WriteLine("{0} isn't 1, 2 or 3!", v))
        .Error().Do(_ => Console.WriteLine("Error"))
        .Exec();
}

If we want to check a range of values, or test the strings for something other than equality, we can use Where:

public static Option<int> IntParser(ValueOrError data)
{
    return data.Match<Option<int>>()
               .Value().Where(s => s.StartsWith("Int:")).Do(s => s.Substring(4).ParseInt())
               .Else(Option<int>.None())
               .Result();
}
Clone this wiki locally