Шаблон соответствует строке Erlang в виде списка в функции

Я недавно начал изучать Erlang и столкнулся с любопытным исключением, которое я не могу объяснить.

Мой исходный код выглядит следующим образом:

-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).

Очень простой код для подсчета количества закрывающих и открывающих фигурных скобок в строке.

В оболочке Erlang, когда я пытаюсь вызвать функцию is_balanced как таковую: balanced_brackets:is_balanced("{}").

Выводится следующая ошибка:

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

Однако, если я передаю аргумент в виде явного списка, сопоставление с образцом работает правильно: balanced_brackets:is_balanced(["{", "}"]).

Разве строки Erlang не являются просто внутренними списками? Почему неправильно сопоставить строку с шаблоном с помощью конструкции [H | T]?

Выполнение BIF is_list("{}"). возвращает true.

Я был бы искренне признателен за чье-нибудь объяснение исключения.

Спасибо.

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


person user3813812    schedule 20.12.2014    source источник


Ответы (2)


Проблема в вашем определении защиты, вы сравниваете с "{", который равен [123], то есть списку с одним элементом, представляющим {.

Ваше сопоставление с образцом правильное, но вы захотите сопоставить с 123 вместо "{" (и то же самое для }, конечно).

Самый простой способ исправить ваш код (и сохранить его читабельным) - это сравнить с [H] вместо H в гвардейцах:

is_balanced([H | T], Opening, Closing) when [H] =:= "{" ->
    is_balanced(T, Opening + 1, Closing);
person filmor    schedule 20.12.2014
comment
Вот и все! Спасибо за краткое объяснение. Пометка как принятая. - person user3813812; 20.12.2014
comment
или вы можете сравнить H с $ {, другим способом представления 123, но с отображением его как символа. - person Pascal; 21.12.2014

Нет необходимости использовать числа для представления символов, как это предлагается в этот ответ. Вместо этого просто используйте символьные константы Erlang. Например, чтобы представить символ {, вы должны использовать ${.

Хороший способ исправить код - полностью избежать защиты и просто сопоставить символы ${ и $} в заголовках функций, например:

is_balanced([${ | T], Opening, Closing) ->
    is_balanced(T, Opening + 1, Closing);
is_balanced([$} | T], Opening, Closing) ->
    is_balanced(T, Opening, Closing + 1);

Затем вам понадобится другое предложение для обработки символов, отличных от ${ и $}, которые отсутствуют в исходном коде:

is_balanced([_ | T], Opening, Closing) ->
    is_balanced(T, Opening, Closing);

И, наконец, оставьте исходное последнее предложение для обработки пустого списка, заканчивая рекурсию:

is_balanced([], Opening, Closing) -> (Opening - Closing).

И еще одно: учитывая имя функции is_balanced, похоже, что она хочет вернуть логическое значение. Если да, измените верхнюю функцию на это:

is_balanced(String) -> is_balanced(String, 0, 0) == 0.
person Steve Vinoski    schedule 20.12.2014