Some Elixir katas - Pt 4
Tags: elixir, kata, algorithms
Published: 2021-04-07 22:22:36

For this kata, I'd like to focus on readability.
The kata is "Valid Parentheses", here's the gist.

> Write a function that takes a string of parentheses, and determines if the order of the parentheses is valid. The function should return true if the string is valid, and false if it's invalid.

And we got some examples:

```
"()"              =>  true
")(()))"          =>  false
"("               =>  false
"(())((()())())"  =>  true
```

So in the stub provided by Codewars, we got this.

```elixir
defmodule ParenthesesValidator do
  def valid_parentheses(string) do
     # it's empty here   
  end
end
```

First thing first, we need to get the value from the `string` parameter and transform it in a list.

One could do:
```elixir
String.split("()", "")
=> ["", "(", ")", ""]
```
But the returned list is dirty with the opening and closing `""` empty string.

```elixir
String.split("()", "", trim: true)
=> ["(", ")"]
```
So we could trim it.

But we also could leverage `String.graphemes/1`

> @spec graphemes(t()) :: [grapheme()]
delegate_to: String.Unicode.graphemes/1
Returns Unicode graphemes in the string as per Extended Grapheme Cluster
algorithm.
The algorithm is outlined in the Unicode Standard Annex #29, Unicode Text
Segmentation (https://www.unicode.org/reports/tr29/).
For details about code points and graphemes, see the String module
documentation.
## Examples
    iex> String.graphemes("Ńaïve")
    ["Ń", "a", "ï", "v", "e"]
    iex> String.graphemes("\u00e9")
    ["é"]
    iex> String.graphemes("\u0065\u0301")
    ["é"]

```elixir
String.graphemes("(())()())")
=> ["(", "(", ")", ")", "(", ")", "(", ")", ")"]
```
Good, no need to trim and no extra empty strings.

A famous cooker once said, "The key for a great dish is a good reduction, it also work in life in general".
He probably knows `Enum.reduce` from Elixir library.
And we're going to use it.

In fact, it's better to know what we want to achieve.
The main goal is to be able to determine if we've a closing parentheses for an opened one.

So declare an accumulator which holds the count of encountered "(" and ")".
Furthermore, we'd like to increment the count of this acc when it's a "(" and decrement when it's a ")".

And compare the accumulator to 0 because that'd say we've for each "(" a ")".

```elixir
defmodule ParenthesesValidator do
  def valid_parentheses(string) do
        string 
        |> String.graphemes
        |> Enum.reduce(0, fn x, acc -> 
            case x do
                "(" -> acc + 1
                ")" -> acc - 1 
                _ -> acc
            end
        end) == 0
  end
end
```

That's the what we get by using the reduce function.
Inside the modifying function, we use a `case` clause to increment or decrement the accumulator value.
At the end of the reduction, we compare it to 0 using `== 0` to return `true` or `false`.

So... it's done right ?

Not really. I omit this test in the suit.

```
")("              =>  false
```

But we got a closing and opening parentheses and our accumulator is equal to 0.
So in fact it's not only related to the count but also to the order of apparition.
Thus, we should not be able increment/decrement if the counter is bellow zero. Which means that a closing parentheses would put the accumulator in `-1` state.
Then, we should not be able to update it. And return false.

Hopefully, guard clause are here for the rescue.
Elixir's guard clauses are directly inherited from Erlang's one.
One must know that you cannot execute function call in guard clause.

Imagine you'd like to guard on the length of a string, like this:

```elixir
when String.length(string) > 10 # would fail
```

But you can do this:
```elixir
when byte_size(string) > 10 # 🎉
```

A little [guard clause cheatsheet].(https://kapeli.com/cheat_sheets/Elixir_Guards.docset/Contents/Resources/Documents/index)

So it's good to know that we got powerful tools to describe what we want to achieve.

```elixir
defmodule ParenthesesValidator do
  def valid_parentheses(string) do
        string 
        |> String.graphemes
        |> Enum.reduce(0, fn x, acc -> 
            case x do
                "(" when acc >= 0 -> acc + 1
                ")" when acc >= 0 -> acc - 1 
                _ -> acc
            end
        end) == 0
  end
end
```

Here's the final version of it.
Reduce, case with guard are the bread and butter of Elixir, being able to use them will help you achieve more easily your goals.

Thanks for reading and happy coding.





Once again, a nice one:

```elixir
defmodule ParenthesesValidator do
  def valid_parentheses(string) do
    case Regex.compile(string) do
      {:ok, _} -> true
      {:error, _} -> false
    end
  end
end
```
Hey but it's a Regex, that's cheating 😂😂😂