What is Pattern Matching?

Asked

Viewed 348 times

5

I’m reading about the Pattern matching and I’m still very confused about this feature because it’s something new for me.

Here are some examples:

{:ok, result} = {:ok, 12}

{:okay, 12}

and

12 = result

12

Questions

  1. What is the Pattern matching?
  2. This feature is only present in functional languages or exists in other languages with other paradigms like Python or C#?
  3. What is the purpose of Pattern matching?

1 answer

6


What is the Pattern matching?

This is not specific to Elixir, and even to functional languages, although it makes more sense in them. All serious language mainstream, especially those who like short, meaningful code and who like killing, one day you will have this mechanism (the others are for non-programmers, although some programmers still use it).

It is a way of making a decision based on a pattern found on an object (in the broad sense of what is object).

By default understand that it is to find some specific way, including your type (structural or nominal) and the constant values in the specific object. So you can say that you want to do a calculation or take a value if the object being analyzed is of type such and in the field or argument x has the specific value.

Do you know when you have an algorithm that identifies whether a photo is of someone or a bug or trying to figure out what the object is? Or a song, or a plagiarized text? All this is an algorithm that tries to find similarities to something he already knows and tell whether it’s the same or not. Of course, the idea in these cases isn’t even to take if it’s accurate, but if it has enough similarity to consider that it’s what you’re looking for.

Another good and more accurate example is Regex. It is only one Pattern matching text, it tries to find a specific format in the text.

The Pattern matching in programming is the same thing, is exact and seeks much simpler patterns involving a basic mathematics. It is a resource that tries to find a situation in the object that matters to what it is doing.

Remembering that a Regex can only tell you if you found the pattern or modify the content based on this pattern, so it’s not just making unrelated decisions, the decision may be to modify the object in a specific way. The same goes for the programming language mechanism.

Note that it is not usually an imperative way of making decisions. Such an example would be used:

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

Here you are defining a function, or two looking the other way. The compiler (or Runtime) will make a decision as to which one you should call them based on their value.

If you’re not used to functional syntax, in other more imperative languages it would be something like this:

function fatorial(0) {
    return 1;
}
function fatorial(n) {
    return n * fatorial(n - 1);
}

When you call fatorial(5) he enters the second function and there calls again the second function as fatorial(4) according to the expression of the call there, which in turn will call again, now with 3, and will call successively until at a certain time the call will be fatorial(0), at that point it no longer calls the second function, it calls the first because it has a better, more specific pattern, when the function argument is 0 then the first one has a matching (marriage) better, and it is she who is executed, and so she closes the repetitions.

Note that they are two completely different functions although they are written together (even to be more readable), it is like a Overload, but the difference of the signature is the value of the argument.

In imperative language you would do with a function and would have a if to decide when to close. In functional languages you do not need this in the code.

For those who are not used to the syntax of certain functional languages seems confusing, and in fact it is a little bit, but it has a logic, it is not something out of the hat. It is a matter of custom and practice. But in fact despite giving an interesting flexibility can hinder understanding.

In his example he is only evaluating whether the expression is valid, without specifying any action unless the result is the value he found.

Your example

What is there in the code is not a simple assignment of values, but in practice you can consider it to be. So :ok hits with :ok and result fits with 12, therefore it assumes this value.

This form of code doesn’t make much sense because it’s a literal, you’re seeing what it is. It’s not that it can’t be used, it can, and a lot of people use it when the data is related, but this particular case usually occurs as a return of a function, i.e., a function that does something, instead of simply returning a result it returns a structure that has the result and a atom indicating whether it worked because the function may not have been able to process what it wanted and the result is not created. So this {:ok, 12} is usually a function return and not the literal written directly, something like that:

{:ok, result} = divide(4, 2)

Then you probably would have one :ok banging and a 2 to be married to the result.

But this:

{:ok, result} = divide(4, 0)

You would have returned one :error that doesn’t match :ok expected, porting is out of standard and the rest doesn’t even matter anymore. Then try to use a result for something will give error. The decision whether to assign a value was based on the pattern found.

For those who don’t know :ok is not a variable, is a literal of the type atom.

Just don’t think there’s magic in there, the compiler puts the decisions to you. The functional paradigm understands that codes should be lean and if it can express more mathematically and less verbosely then it should be done so. These languages are more declarative, therefore you say what you want and you don’t say what to do, the language turns to what to do.

But if you want to do something useful you need to write something else:

write_line(case divide(4, 0) do
    {:ok, result} -> deu certo, o valor é #{result}"
    {:error, _} -> "lamento, deu erro"
end)

On the page following linked in the question shows how it works by making decisions in a more traditional way.

There may be some error in the code and there may be an easier way to do it, I don’t usually use Elixir, but here’s the idea.

This feature is only present in functional languages or exists in other languages with other paradigms like Python or C#?

Exists in any language they found useful, including in C# and others. Of course, in general they tend to have more limitations, for example you cannot decide a function call just by your signature considering the value, you can even make that decision, but you need to be more explicit, compiler does not make the decision alone as occurs in more functional languages.

In C# for example you can have something like this:

(var ok, var result) = TryDivide(4, 0);

But it doesn’t Pattern matching, the two variables will be assigned and then if you want you will have to be explicit in using a if. And if the value is invalid, nothing prevents you from using the result. Unlike Elixir, you can do something wrong with it. But today you can do something like this that is safer:

WriteLine(TryDivide(4, 0) switch {
    (true, result) => $"deu certo, o valor é {result}",
    (false, _) => "lamento, deu erro" //não usará a variável mesmo, então descarta
});

So even though Pattern matching language is still imperative, you say what to do, which in and many cases is even necessary.

Part of the difference is that language doesn’t have the atom, but could use a enum in place, because at the bottom is (almost) the same thing. In a way a boolean is a enum more specific. A enum would make it more explicit that you have a ok or error and not just if the ok is true or false.

What is the purpose of Pattern matching?

I answered in part about Elixir.

We can say that it is a way of simplifying codes where you must decide what to do within complex (or not so) conditions. Instead of simply making a comparison (which can even be complex and involve multiple nuances) you say something you expect to find on an object and if that pattern is found you should perform a specific action, probably resulting in a value through an expression. So in a way he replaces a if (in fact in functional languages a little more pure is the only way to make decisions).

He is a switchthat everyone knows much more sophisticated than is usually just a Pattern matching simplified, since the only standard it adopts is whether the value of an object has a specific value.

With the Pattern matching you can check if the object is of a certain type, you can analyze if it has a certain structure, if it has certain values in part of its structure and consider the others as variable part, finally if it meets certain criteria of how the object behaves quite flexibly (the language needs to be prepared for every possible flexibility). And it’s possible to have more sophisticated conditions beyond the standard, just like with a if (in general this is an extra check to the standard).

Who is very used to imperative languages suffers to adapt with this syntax, especially in languages that allow a more imperative form optionally, one tends to use what he has accustomed.

Browser other questions tagged

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