What is Pattern matching in functional languages?

Asked

Viewed 156 times

9

When reading about the functional paradigm, I realized that most languages have a common characteristic, the Pattern matching.

Contextualizing for a programmer like me, accustomed to the object-oriented and imperative paradigms, which would be Pattern matching and where would it be useful? There is something similar in languages like C++, C# or Java?

1 answer

6


In C# there is yes, since the version 7 and from there to here are improving a lot what he can do. I’ve seen proposal to put in C++, but any language can do more or less the same, can only take much more work and need help library not to be impractical, and will be ugly (I replied about Swift, Rust and other languages have some form). Some examples in C#:

switch (shape) {
    case Square s when s.Side == 0:
    case Circle c when c.Radius == 0:
        return 0;
    case Square s:
        return s.Side * s.Side;
    case Circle c:
        return c.Radius * c.Radius * Math.PI;
    default:
        throw new ArgumentException(message: "shape is not a recognized shape", paramName: nameof(shape));
}

This seems more obvious that according to the conditions he enters the case, then the first one needs the dice to be like Shape and the object that is stored in the variable s have your property Side equal to 0, the same happens with Circle but then the condition is different. In fact C# can do the same even with a if, but it would still be a Pattern matching because it does more than analyze a condition, it looks for a more general pattern, including the way the compiler handles can be different and optimized. Here you are using a syntax that can already be considered old.

static string Display(object o) => o switch {
    Point { X: 0, Y: 0 }         p => "origin",
    Point { X: var x, Y: var y } p => $"({x}, {y})",
    _                              => "unknown"
};

I put in the Github for future reference.

Here it’s more complex because it’s trying to see if an object is in a certain way, in which case the object has to be of the type Point and the properties X and Y should be set to 0 in the first option and if it is a point but it is not set to 0, then you should assign the properties to variables that will be used right away, and it ends up resulting in a value that indicates that you have not found a pattern.

As its name says, it is a mechanism that tries to find patterns in data, if it finds in the data being analyzed a pattern equal to that determined in a clause of Pattern matching then the code does something linked there, usually result in a value, although it may have some algorithm to get there.

Purely functional languages do not usually have a if, then this is the selector mechanism of what to do and what makes conditional decisions. You can use it simply and be like a if, or you can look for more complex patterns as the language leaves you. These languages usually have a simple and short way of doing this operation. Example:

f 0 = 1
f n = n * f (n - 1)

I put in the Github for future reference.

This is creating a function f() which will run the formula recursively whenever it does not meet the first case that looks for the default that the function call argument is 0, when the result is 1, otherwise the default then considers that the argument is received in n and this parameter is used to multiply with the result of the call of the function itself passed the n except 1. All without if, so the paradigm is functional and not imperative, you don’t order something do you create a function that does something within a pattern.

At first he may look something like switch, so much so that it has language that uses the same syntax, but it is much more powerful, not only because it can declare local variables for use at that moment but it can perform complex analyses with very simple syntax. Moreover the switch is usually a data check optimization that has relationship and the Pattern matching because it is more complex, it is not usually optimized in the same way, but it can be in other ways.

Except in purely functional languages that do not possess if or something similar (the not pure ones possess) it is absolutely unnecessary, however it is convenient when the logic you are creating must perform according to a found data pattern. It doesn’t change much unless you start to see the problems differently and you step away from the imperative a little (tell you what to do) to go to the declarative (tell you what you want). It’s just a different style of writing, it’s a way of expressing something closer to the problem. That’s why it becomes popular among programmers, and the other people who code will never use it :)

Of course, there are those who abuse too. When it is simpler to make a if or switch Just do it like this. It’s the same recursion that in imperative language doesn’t make sense in most scenarios and a loop solves better, but some people think they’ll find it smarter if they use recursion :P

Needless to say, it is the horror of object-oriented purists. In fact it encourages making the code less object-oriented and making the decision about what type to use in the algorithm and not in the data structure, it goes against the current of polymorphism, although the Pattern matching is to some extent a form of polymorphism, since a function with a different signature will be called according to the (s) argument(s) passed, making multiple dispatch (languages more mainstream imperatives do not usually have this ability even having the Pattern matching most imperative). Most of the languages that were said to be "object-oriented" are adopting this mechanism because they want to get away from the plague of "OOP at any cost" that some preach.

It may be harder to add new types in an operation in some scenarios, but it is easier to add operations to the types in all scenarios.

Every mechanism in the right place.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.