如何使用函数值在 erlang 中进行大小写切换?



尽管看起来可以工作,但该程序正在崩溃。我不明白为什么。我正在尝试完成深度合并并需要条件逻辑。

给定以下列表:

ManOne = #{ "Bob" => #{"Sagget" => #{}} }
ManTwo = #{ "Bob" => #{"Daniels" => #{}} }

我正在尝试按如下方式比较它们,此函数按预期返回 true:

check_if_same(M1, M2) -> 
{ok, lists:sort( maps:keys(M1) ) == lists:sort( maps:keys(M2) )}.
merger(M1, M2) ->
M1_Keys = maps:keys(M1),
M2_Keys = maps:keys(M2),
do_merge(M1, M2, M1_Keys).
do_merge(M1, M2, [Head|Tail]) ->
Check = check_if_same(M1, M2),
io:fwrite("Check is: ~pn", [Check]),
case Check of 
{ok, true} -> 
io:fwrite("truen");
{ok, false} ->
io:fwrite("falsen")
end,
do_merge(M1, M2, Tail);
do_merge(M1, M2, []) -> 
ok.
check_if_same(M1, M2) -> 
{ok, lists:sort( maps:keys(M1) ) == lists:sort( maps:keys(M2) )}.

给出以下输出:

Check is: {ok,true}
true
{"init terminating in do_boot",{{badmap,ok},[{maps,keys,[ok],[]},{helloworld,merger,2,[{file,"helloworld.erl"},{line,9}]},{init,start_em,1,[]},{init,do_boot,3,[]}]}}
init terminating in do_boot ()
Crash dump is being written to: erl_crash.dump...done

让我们先回顾一下您的问题,因为我们可以做出一些误解和/或更正。

您的描述

尽管看起来可以工作,但该程序仍在崩溃。我不明白为什么。我正在尝试完成深度合并并需要条件逻辑。

给定以下列表:

ManOne = #{ "Bob" => #{"Sagget" => #{}} }
ManTwo = #{ "Bob" => #{"Daniels" => #{}} }

请注意,以上不是列表,而是地图,功能完全不同。

出于所有意图和目的,映射是一个查找表,直到它包含 ~31 个键/值对。

此时,它变成了一个哈希图(这可以通过查看元素来查看,因为它们在映射成为哈希图后变得无序(。

我正在尝试按如下方式比较它们,此函数按预期返回 true:

check_if_same(M1, M2) -> 
{ok, lists:sort( maps:keys(M1) ) == lists:sort( maps:keys(M2) )}.

这是断言相等的错误方式;在 erlang 中,建议不要使用==来检查相等性。

相反,应使用=:=

这样做的原因是==检查它正在比较的元素的类型,只取一个模糊值 - 即1 == 1.0将返回 true,但1 =:= 1.0将返回 false。

就个人而言,我建议使用 Erlang 的模式匹配来检查您的值。

这可以使用以下代码片段实现:

-spec check_if_same(M1 :: map(), M2 :: map()) -> boolean().
check_if_same(M1, M2) ->
SortedKeys1 = lists:sort(maps:keys(M1)),
SortedKeys2 = lists:sort(maps:keys(M2)),
%% We hide the implementation of the function in
%%  a function with the same name suffixed with an
%%  underscore. This allows us to have a public api
%%  but keep the implementation internal which allows
%%  the code to be a bit cleaner.
check_if_same_(SortedKeys1, SortedKeys2). 
%% If they're both empty then we've gone through
%%  every key meaning that they must be identical
check_if_same_([], []) ->
true;
%% If the current Key on both heads is the same
%%  then recurse and check the next and so on
check_if_same_([Key|Tail1], [Key|Tail2]) ->
check_if_same_(Tail1, Tail2);
%% If we get anything else, e.g more keys in 
%%  one than the other or the keys don't match,
%%  then we'll fall in to this case. 
%% As we know anything that falls in to this 
%%  case doesn't match, we just return false
check_if_same_(Keys1, Keys2) when is_list(Keys1), is_list(Keys2) ->
false.

请注意,在上面的代码片段中,我只返回了truefalse- 我对更干净的代码的建议是保持以下格式;

  • ok- 这通常用于您关心效果而不是回报的函数
  • true|false- 这通常用于比较函数,即is_binary/1is_function/1
  • {ok, Value}- 这通常适用于您关心返回值的任何函数
  • {error, Reason}- 当您预计会出现错误时,都会使用此功能,以便您可以使用易于匹配的格式将错误重新发送到链中

您的代码片段

merger(M1, M2) ->
M1_Keys = maps:keys(M1),
%% Note that you don't use the M2Keys here so you don't need to do the work to get them
M2_Keys = maps:keys(M2),
do_merge(M1, M2, M1_Keys).
do_merge(M1, M2, [Head|Tail]) ->
Check = check_if_same(M1, M2),
%% It's generally recommended to stick to io:format/2 rather than io:fwrite/2
io:fwrite("Check is: ~pn", [Check]), 
case Check of 
{ok, true} -> 
io:fwrite("truen");
{ok, false} ->
io:fwrite("falsen")
end,
do_merge(M1, M2, Tail);
do_merge(M1, M2, []) -> 
ok.
check_if_same(M1, M2) -> 
{ok, lists:sort( maps:keys(M1) ) == lists:sort( maps:keys(M2) )}.

现在,上面的代码片段(除了效率低下(完全没问题,可以按预期工作

给出以下输出:

Check is: {ok,true}
true
{"init terminating in do_boot",{{badmap,ok},[{maps,keys,[ok],[]},{helloworld,merger,2,[{file,"helloworld.erl"},{line,9}]},{init,start_em,1,[]},{init,do_boot,3,[]}]}}
init terminating in do_boot ()
Crash dump is being written to: erl_crash.dump...done

此故障转储是真正的问题所在;

Check is: {ok,true}
true

由此我们可以看出,我们

  • 点击 io:fwrite/2 (io:fwrite("Check is: ~pn", [Check])(
  • 在大小写中输入了{ok, true}路径 (io:fwrite("truen")(

下一行是我们看到实际问题的地方,让我们分解一下:

  • "init terminating in do_boot"- 启动时失败,这可能是在运行脚本或启动应用程序时

现在让我们分解一下这个元组:

{
{badmap,ok}, %% The function we called expected a map and we passed in 'ok'
[
{maps,keys,[ok],[]}, %% We called maps:keys/1 with 'ok' as an arg
{helloworld,merger,2,[{file,"helloworld.erl"},{line,9}]}, %% This was called at helloworld:merger/2 (helloworld.erl:9)
{init,start_em,1,[]},{init,do_boot,3,[]} %% We failed on start up
]
}

我们可以从中得到的是,您在helloworld.erl的第9 行使用无效值ok调用代码中的合并

缺少一些信息。尽管此代码看起来像初稿或步骤,但它按预期工作。我在外壳中对其进行了测试并得到了这个:

-module (merger).
-compile(export_all).
merger(M1, M2) ->
M1_Keys = maps:keys(M1),
M2_Keys = maps:keys(M2),
do_merge(M1, M2, M1_Keys).
do_merge(M1, M2, [Head|Tail]) ->
Check = check_if_same(M1, M2),
io:fwrite("Check is: ~pn", [Check]),
case Check of 
{ok, true} -> 
io:fwrite("truen");
{ok, false} ->
io:fwrite("falsen")
end,
do_merge(M1, M2, Tail);
do_merge(M1, M2, []) -> 
ok.
check_if_same(M1, M2) -> 
{ok, lists:sort( maps:keys(M1) ) == lists:sort( maps:keys(M2) )}.
test() ->
merger(#{ "Bob" => #{"Sagget" => #{}} },#{ "Bob" => #{"Daniels" => #{}} }).

这给了:

8> c(merger).
merger.erl:3: Warning: export_all flag enabled - all functions will be exported
merger.erl:7: Warning: variable 'M2_Keys' is unused
merger.erl:9: Warning: variable 'Head' is unused
merger.erl:19: Warning: variable 'M1' is unused
merger.erl:19: Warning: variable 'M2' is unused
{ok,merger}
9> merger:test().
Check is: {ok,true}
true
ok
10>

也许您还可以告诉我们合并ManOneManTwo的预期结果是什么

相关内容

  • 没有找到相关文章

最新更新