Cannot use function in Guard. Alternative Implementation Suggestions

I am trying to create a prime factorizer using a farm method .

This line generates an error.

find_factors(A, B, FactorThis) when is_a_square(B) == true -> 

calling local / imported function is_a_square / 1 is illegal in protection

The only possible alternative that I see in this implementation is to use some case argument in the function. I avoided this, as this could ruin the tail recursion. I'm Erlang noob. What other methods of implementing this function exist?

 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

Ed. fixed argument in call to calculate_new_b

Added missing get_int_part_of_sqrts.

+4
source share
2 answers

Erlang deliberately restricts which functions you can call in the guards. Here is a fairly recent discussion of the rationale for this, its strengths and weaknesses.

The only way is to use case . You can easily rewrite this code to use 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). 

Please note that the above code is still correctly recursive.

(I modified your code a bit to pull out parts that I assume you didn't want there)

+12
source

Here is another way to reorganize the problem.

Add the desired guard function as an argument to the caller. This turns it from a function with possible side effects to true or false, which have no side effects. Then a direct match will be performed with the sample.

 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)). 
+2
source

All Articles