Search code examples
erlangerlang-shell

Pattern match Erlang string as list in function


I have recently started to study Erlang and have encountered a curious exception which I cannot explain.

My source code is as follows:

-module(balanced_brackets).                                                                                                              
-author("Irrelevant").
-compile(export_all).

is_balanced(String) -> is_balanced(String, 0, 0).

is_balanced([H | T], Opening, Closing) when H =:= "{" ->
    is_balanced(T, Opening + 1, Closing);
is_balanced([H | T], Opening, Closing) when H =:= "}" ->
    is_balanced(T, Opening, Closing + 1);
is_balanced([], Opening, Closing) -> (Opening - Closing).

Very basic code to count the number of closing and opening curly brackets in a string.

In the Erlang shell, when I try to call the function is_balanced as such: balanced_brackets:is_balanced("{}").

The following error is output:

** exception error: no function clause matching balanced_brackets:is_balanced("{}",0,0) (balanced_brackets.erl, line 7)

However, if I pass the argument as an explicit list, pattern matching works correctly: balanced_brackets:is_balanced(["{", "}"]).

Aren't Erlang strings simply lists internally? Why is it incorrect to pattern match a string using the construct [H | T]?

Executing the BIF is_list("{}"). returns true.

I would sincerely appreciate somebody's explanation for the exception.

Thank you.

Erlang/OTP 17 [erts-6.2] [source-aaaefb3] [64-bit] [smp:2:2] [async-threads:10] [hipe] [kernel-poll:false]


Solution

  • The problem is your guard definition, you are comparing to "{" which is [123], i.e. a list with one element representing {.

    Your pattern matching is correct, but you will want to match against 123 instead of "{" (and the same for } of course).

    The easiest way to fix your code (and keep it readable) is to compare to [H] instead of H in the guards:

    is_balanced([H | T], Opening, Closing) when [H] =:= "{" ->
        is_balanced(T, Opening + 1, Closing);