不允许在Guard中使用函数。需要替代实施的建议

时间:2011-09-19 17:32:24

标签: erlang

我正在尝试使用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).

Research1

Research2

编辑。 在调用calculate_new_b

时修复了参数

添加了缺少的get_int_part_of_sqrts。

2 个答案:

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