Excessive use of guards in Erlang?

I have the following function that takes a number like 5 and creates a list of all numbers from 1 to that number, so create (5). returns [1,2,3,4,5].

I already used defenders, I think, and I was wondering if there is a better way to write the following:

create(N) -> create(1, N). create(N,M) when N =:= M -> [N]; create(N,M) when N < M -> [N] ++ create(N + 1, M). 
+4
source share
3 answers
 create(N,N) -> [N]; create(N,M) -> [N|create(N + 1, M)]. % Don't use ++ to prefix a single element. 

This is not exactly the same (you can put -5), but it behaves the same if you supply significant inputs. In any case, I would not bother with additional verification, since the process will work very quickly in any case.

By the way, you have a problem with recursive depth with code as is. This will fix this:

 create(N) -> create(1, N, []). create(N, N, Acc) -> [N|Acc]; create(N, M, Acc) -> create(N, M - 1, [M|Acc]). 
+3
source

Defender N < M may be useful. In general, you do not need a guard for equality; you can use pattern matching.

 create(N) -> create(1, N). create(M, M) -> [M]; create(N, M) when N < M -> [N | create(N + 1, M)]. 

You also usually want to write functions so that they are tail recursive, in which the general idiom should be written to the head and then reversed at the end.

 create(N) -> create(1, N, []). create(M, M, Acc) -> lists:reverse([M | Acc]); create(N, M, Acc) when N < M -> create(N + 1, M, [N | Acc]). 

(Of course, in this particular example, you can alternatively build the results in the reverse order, up to 1 instead of M, which would make calling lists:reverse unnecessary.)

If create/2 (or create/3 ) is not exported, and you set the corresponding protector to create/1 , an additional N < M protector may be overflowed. Usually I test only exported functions and trust my own internal functions.

+6
source

I really don't think you used used guards. There are two cases:

The first is an explicit equality test in the first create / 2 clause

 create(N, M) when N =:= M -> [M]; 

Some suggested converting this to use pattern matching, for example

 create(N, N) -> [N]; 

In this case, it does not make any difference, since the compiler internally converts the version of the pattern matching into what you wrote. You can safely choose which version you consider the best in each case.

In the second case, you need some form of sanity check so that the value of the argument is in the range that you expect. Execution in each loop is not necessary, and I would move it to the equivalent test in create / 1:

 create(M) when M > 1 -> create(1, M). 

If you want to use a battery, I would personally use the version of count, since it keeps the list reversed at the end. If the list is not long, I think the difference is very small, and you can choose a version that you will understand. In any case, it is very easy to change later if you consider it critical.

+1
source

Source: https://habr.com/ru/post/1306746/


All Articles