我正在尝试使用fermats method创建一个素数因子。
此行生成错误
find_factors(A, B, FactorThis) when is_a_square(B) == true ->
调用本地/导入函数is_a_square / 1是非法的守卫
我在这个实现中看到的唯一可能的替代方法是在函数中使用某种case语句。我正在避免这种情况,因为它可能搞砸尾部递归。我是Erlang noob。 有哪些其他方法可以实现此功能?
get_int_part_of_sqrt(N) ->
trunc(math:sqrt(N)).
is_a_square(N) ->
get_int_part_of_sqrt(N) * get_int_part_of_sqrt(N) == N.
calculate_new_b(A, FactorThis) ->
NewB = trunc(abs((A * A) - FactorThis)),
io:format("Calculate_new_b A^2 ~w- FT ~w= NB ~w ~n",[A*A,FactorThis,NewB]),
find_factors(A, B, FactorThis) when is_a_square(B) == true ->
io:format("find_factors true ~w ~w~n", [A, B]),
{ok, A + get_int_part_of_sqrt(B), A - get_int_part_of_sqrt(B)};
find_factors(A, B, FactorThis) ->
io:format("find_factors false ~w ~w~n", [A, B]),
NewA = A + 1,
NewB = calculate_new_b(NewA, FactorThis),
find_factors(NewA, NewB, FactorThis).
编辑。 在调用calculate_new_b
时修复了参数添加了缺少的get_int_part_of_sqrts。
答案 0 :(得分:12)
Erlang故意限制你可以在守卫中调用哪些功能。 Here's最近讨论了这个的理由,优点和缺点。
唯一的方法是使用case
。您可以非常轻松地重写此代码以使用case
:
find_factors(A, B, FactorThis) ->
case is_a_square(B) of
true -> io:format(" find_factors true ~w ~w~n", [A, B]),
{ok, A + B, A - B};
false-> io:format(" find_factors false ~w ~w~n", [A, B]),
NewA = A + 1,
NewB = calculate_new_b(NewA, FactorThis),
find_factors(NewA, NewB, FactorThis).
请注意,上面的代码仍然是正确的尾递归。
(我修改了你的代码以取出我猜你不想拥有的那些部分)
答案 1 :(得分:2)
这是另一种围绕这个问题进行重构的方法。
在呼叫者处添加所需的保护功能作为参数。这将其从具有可能副作用的函数转变为真或假,其没有副作用。然后直接模式匹配将完成这项工作。
main() ->
List2 = find_factors_2 (10, 5, 105, is_a_square(5)),
io:format("method 2 ~w~n", [List2]).
find_factors_2(A, B, _FactorThis, true) ->
Offset = get_int_part_of_sqrt(B),
{A + Offset, A - Offset};
find_factors_2(A, _B, FactorThis, false) ->
NewA = A + 1,
NewB = calculate_new_b(NewA, FactorThis),
find_factors_2(NewA, NewB, FactorThis, is_a_square(NewB)).