由于 types/sizes 不同,此子句无法匹配
this clause cannot match because of different types/sizes
我尝试在 erlang 中实现 binary_search :
binary_search(X , List) ->
case {is_number(x) , is_list(List)} of
{false , false} -> {error};
{false , true} -> {error} ;
{true , false} -> {error} ;
{true , true} ->
Length = length(List) ,
case Length of
0 -> {false};
1 -> case lists:member(X , List) of
true -> {true};
false -> {false}
end ;
_ ->
Middle = (Length + 1) div 2 ,
case X >= Middle of
true -> binary_search(X , lists:sublist(List , Middle , Length));
false -> binary_search(X , lists:sublist(List , 1 , Middle))
end
end
end .
然而,当我尝试编译它时,出现以下错误:"this clause cannot match because of different types/sizes" 在两行中:
{true , false} -> {error} ;
{true , true} ->
is_number(x) 将始终 return 错误,因为您输入错误:x 而不是 X,原子而不是变量。
顺便说一句,我不知道你遇到了什么,但整个代码可以写成:
binary_search(X , [_|_] = List) when is_number(X) ->
{lists:member(X,List)};
binary_search(_,_) -> {error}.
上下文:OP 的 post 似乎是一个学习示例——试图理解 Erlang 中的二进制搜索——并被视为以下示例(因此调用 io:format/2
内部函数的每次迭代)。在生产中,lists:member/2
应该按照 Steve Vinoski 在下面的评论中指出的那样使用,或者 lists:member/2
由函数头保护,如 Pascal 的回答。下面是二分查找的手动实现。
Pascal 的拼写错误是正确的,但此代码存在更多基本问题。让我们看看是否可以完全避免这种嵌套大小写检查的需要,而不仅仅是查找拼写错误。
(上面写的代码无论如何都不起作用,因为 X
不应该代表索引的值,而是代表该索引处的值,所以 Middle
可能会从不匹配 X
。此外,还有另一个问题:您没有涵盖所有基本情况(您应该停止递归的情况)。因此下面的内部函数将它们全部覆盖为函数头中的匹配项, 因此搜索的工作方式更加明显。顺便说一下,请注意 X > Value
时的 Middle + 1
;考虑为什么这是必要的。)
关于Erlang风格的两个主要笔记
第一:如果你收到错误的数据,直接崩溃,不要return一个错误。考虑到这一点,请考虑使用警卫。
第二:如果您发现自己处理了很多案例,您通常可以通过命名函数来简化您的生活。这给了你两个好处:
- 比在嵌套
case
表达式中获得的崩溃报告要好得多。
- 一个命名的纯函数如果足够小,就可以很容易地进行测试,甚至可以很容易地进行形式验证——这也很酷。 (作为旁注,测试的信仰有时会考验我的耐心和理智,但是当你有纯函数时,你 实际上可以 至少测试你程序的那些部分——所以提炼出来尽可能多地做这种事情是一个巨大的胜利。)
下面我都做了这两个,这应该可以避免您 运行 遇到的问题,并使事情更容易 read/sort 通过心理:
%% Don't return errors, just crash.
%% Only check the data on entry.
%% Guarantee the data is sorted, as this is fundamental to binary search.
binary_search(X, List)
when is_number(X),
is_list(List) ->
bs(X, lists:sort(List)).
%% Get all of our obvious base cases out of the way as matches.
%% Note the lack of type checking; its already been done.
bs(_, []) -> false;
bs(X, [X]) -> true;
bs(X, [_]) -> false;
bs(X, List) ->
ok = io:format("bs(~p, ~p)~n", [X, List]),
Length = length(List),
Middle = (Length + 1) div 2,
Value = lists:nth(Middle, List),
% This is one of those rare times I find an 'if' to be more
% clear in meaning than a 'case'.
if
X == Value -> true;
X > Value -> bs(X, lists:sublist(List, Middle + 1, Length));
X < Value -> bs(X, lists:sublist(List, 1, Middle))
end.
我尝试在 erlang 中实现 binary_search :
binary_search(X , List) ->
case {is_number(x) , is_list(List)} of
{false , false} -> {error};
{false , true} -> {error} ;
{true , false} -> {error} ;
{true , true} ->
Length = length(List) ,
case Length of
0 -> {false};
1 -> case lists:member(X , List) of
true -> {true};
false -> {false}
end ;
_ ->
Middle = (Length + 1) div 2 ,
case X >= Middle of
true -> binary_search(X , lists:sublist(List , Middle , Length));
false -> binary_search(X , lists:sublist(List , 1 , Middle))
end
end
end .
然而,当我尝试编译它时,出现以下错误:"this clause cannot match because of different types/sizes" 在两行中:
{true , false} -> {error} ;
{true , true} ->
is_number(x) 将始终 return 错误,因为您输入错误:x 而不是 X,原子而不是变量。
顺便说一句,我不知道你遇到了什么,但整个代码可以写成:
binary_search(X , [_|_] = List) when is_number(X) ->
{lists:member(X,List)};
binary_search(_,_) -> {error}.
上下文:OP 的 post 似乎是一个学习示例——试图理解 Erlang 中的二进制搜索——并被视为以下示例(因此调用 io:format/2
内部函数的每次迭代)。在生产中,lists:member/2
应该按照 Steve Vinoski 在下面的评论中指出的那样使用,或者 lists:member/2
由函数头保护,如 Pascal 的回答。下面是二分查找的手动实现。
Pascal 的拼写错误是正确的,但此代码存在更多基本问题。让我们看看是否可以完全避免这种嵌套大小写检查的需要,而不仅仅是查找拼写错误。
(上面写的代码无论如何都不起作用,因为 X
不应该代表索引的值,而是代表该索引处的值,所以 Middle
可能会从不匹配 X
。此外,还有另一个问题:您没有涵盖所有基本情况(您应该停止递归的情况)。因此下面的内部函数将它们全部覆盖为函数头中的匹配项, 因此搜索的工作方式更加明显。顺便说一下,请注意 X > Value
时的 Middle + 1
;考虑为什么这是必要的。)
关于Erlang风格的两个主要笔记
第一:如果你收到错误的数据,直接崩溃,不要return一个错误。考虑到这一点,请考虑使用警卫。
第二:如果您发现自己处理了很多案例,您通常可以通过命名函数来简化您的生活。这给了你两个好处:
- 比在嵌套
case
表达式中获得的崩溃报告要好得多。 - 一个命名的纯函数如果足够小,就可以很容易地进行测试,甚至可以很容易地进行形式验证——这也很酷。 (作为旁注,测试的信仰有时会考验我的耐心和理智,但是当你有纯函数时,你 实际上可以 至少测试你程序的那些部分——所以提炼出来尽可能多地做这种事情是一个巨大的胜利。)
下面我都做了这两个,这应该可以避免您 运行 遇到的问题,并使事情更容易 read/sort 通过心理:
%% Don't return errors, just crash.
%% Only check the data on entry.
%% Guarantee the data is sorted, as this is fundamental to binary search.
binary_search(X, List)
when is_number(X),
is_list(List) ->
bs(X, lists:sort(List)).
%% Get all of our obvious base cases out of the way as matches.
%% Note the lack of type checking; its already been done.
bs(_, []) -> false;
bs(X, [X]) -> true;
bs(X, [_]) -> false;
bs(X, List) ->
ok = io:format("bs(~p, ~p)~n", [X, List]),
Length = length(List),
Middle = (Length + 1) div 2,
Value = lists:nth(Middle, List),
% This is one of those rare times I find an 'if' to be more
% clear in meaning than a 'case'.
if
X == Value -> true;
X > Value -> bs(X, lists:sublist(List, Middle + 1, Length));
X < Value -> bs(X, lists:sublist(List, 1, Middle))
end.