我最近开始研究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 shell中,当我尝试调用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]
答案 0 :(得分:2)
根据this answer的建议,无需使用数字来表示字符。相反,只需使用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);
最后,保持原始的final子句处理空列表,结束递归:
is_balanced([], Opening, Closing) -> (Opening - Closing).
还有一件事:给定函数名is_balanced
,它似乎想要返回一个布尔值。如果是这样,请将顶部函数更改为:
is_balanced(String) -> is_balanced(String, 0, 0) == 0.
答案 1 :(得分:1)
问题在于您的保护定义,您要与"{"
[123]
进行比较,即包含一个代表{
的元素的列表。
您的模式匹配是正确的,但您希望与123
而不是"{"
匹配(当然,}
也是如此)。
修复代码(并保持可读性)的最简单方法是在守卫中与[H]
而不是H
进行比较:
is_balanced([H | T], Opening, Closing) when [H] =:= "{" ->
is_balanced(T, Opening + 1, Closing);