F# has a feature enabling users to extend pattern matching:
let (|Even|Odd|) n = if n % 2 = 0 then Even else Odd
match 3 with | Odd -> printfn "odd"
             | Even -> printfn "even"
or:
(** Parsing date from any of the formats: MM/DD/YY, MM/DD/YYYY, YYYY-MM-DD *)
let parseDate = function
| ParseRegex "(\d{1,2})/(\d{1,2})/(\d{1,2})$" [Integer m; Integer d; Integer y]
   -> new DateTime(y + 2000, m, d)
| ParseRegex "(\d{1,2})/(\d{1,2})/(\d{3,4})" [Integer m; Integer d; Integer y]
   -> new DateTime(y, m, d)
| ParseRegex "(\d{1,4})-(\d{1,2})-(\d{1,2})" [Integer y; Integer m; Integer d]
   -> new DateTime(y, m, d)
The magic happens in the ParseRegex pattern which is defined as such:
(** Definition of the MatchRegex active pattern *)
let (|ParseRegex|_|) rgx s = match Regex(rgx).Match(s) with
                         | m when not m.Success -> None
                         | m -> Some(List.tail [for x in m.Groups->x.Value])
The ParseRegex can now be used everywhere and the whole point of it is that parsing out parts of strings can be done in a very concise way.
Does Scala have a similar feature?
In C# this level of conciseness seems hard to achieve but maybe some clever trick using implicit conversion or so could help?
Disclaimer: I don't know F#.
In scala, if a value has a method named unapply (or unapplySeq), then it will be used in pattern matching.
The definition of unapply is:
object Example {
    def unapply(t: T): Option[(T1, ..., Tn)] = ...
}
If None is return it means no match, Some((t1, ..., tn)) means a match is successful and can be bound to values t1 to tn
And then it can be used as:
value match {
  case Example(t1, ..., tn) => ...
}
If the matching can have dynamic number of results, then unapplySeq is used which returns Option[List[T]]
Finally, if no variables need to be bound when matching, unapply can just return a Boolean
Examples:
val Date = ""(\d{1,2})/(\d{1,2})/(\d{1,2})$".r
"12/12/12" match {
   case Date(m, d, y) => ...
}
The .r method turns a string into a Regex. That class has an unapplySeq method which matches the groups in the regex.
case class Person(name: String, age: Int)
somePerson match {
    case Person(name, age) => ...
}
In this case, the syntax case class creates an singleton object with the same name (Person) with an unapply method matching the constructor arguments.
UPDATE: Here's how to define Even and Odd First, some generalization. Both Even and Odd can be expressed via a function, but we need to make this function conform to the extractors spec, that is, apply it via unapply
class BooleanExtractor[T](f: T => Boolean) { 
  def unapply(t: T) = f(t)
}
Now, we can use like this (showing two ways)
val Even = new BooleanExtractor[Int](_ % 2 == 0)
object Odd extends BooleanExtractor[Int](_ % 2 == 1)
And use:
scala> 3 match {
     |   case Even() => println("even")
     |   case Odd() => println("odd")
     | }
odd
                        You can achieve this functionality by way of a scala feature called Extractors.
For your even/odd example:
object Even {
  def unapply(x:Int) = if (x % 2 == 0) Some(x) else None
}
object Odd {
  def unapply(x:Int) = if (x % 2 == 1) Some(x) else None
}
3 match {
  case Even(x) => println("even")
  case Odd(x) => println("odd")
}
                        You can achieve the same in Scala. The concept is called Extractors. The syntax to define them is a bit uglier than in F# it seems. I'll provide the first example:
scala> object Even {def unapply(z: Int) = (z%2 == 0)}                      
defined module Even    
scala> object Odd {def unapply(z: Int) = (z%2 != 0)}                       
defined module Odd    
scala> 2 match {
     | case Even() => "even";
     | case Odd() => "odd";
     | }
res10: java.lang.String = even
Your second example works, too. You have to return the DateTime objects from the unapply method. I provide a link here where you can read more on the topic.
I noticed that no one added C# code for this, so I made an attempt of reproducing the feature in code here: https://siderite.dev/blog/c-equivalent-to-f-active-patterns.html Basically I created one or two helper classes that then would allow me to write code like this:
var apInt = Option<int>.From<string>(s =>
{
    int i;
    return System.Int32.TryParse(s, out i) 
        ? new Option<int>(i) 
        : Option<int>.Empty;
});
var apBool = Option<bool>.From<string>(s =>
{
    bool b;
    return System.Boolean.TryParse(s, out b)
        ? new Option<bool>(b)
        : Option<bool>.Empty;
});
var testParse = new Action<string>(s =>
{
    FluidFunc
        .Match(s)
        .With(apInt, r => Console.WriteLine($"The value is an int '{r}'"))
        .With(apBool, r => Console.WriteLine($"The value is an bool '{r}'"))
        .Else(v => Console.WriteLine($"The value '{v}' is something else"));
});
testParse("12");
testParse("true");
testParse("abc");
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With