В Эрланге есть способ создать пустую функцию? - PullRequest
9 голосов
/ 14 июля 2009

Я пишу функцию Erlang, которая печатает каждое четное число с точностью до заданного параметра.

Пока что я написал функцию с охранниками так:

printEven(I,N) when I < N ->
  if
    I rem 2 == 0 -> io:format("~p~n",[I]), printEven(I+1,N);
    I rem 2 == 1 -> printEven(I+1,N)
  end;
printEven(I,N) ->
   io:format("Done").

Мне бы очень хотелось, чтобы последний случай просто выходил автоматически и не печатал ничего в функции. Я пытался просто удалить его, но затем возникает ошибка, поскольку, когда рекурсия завершена, выдается ошибка.

Как я могу это сделать? Есть ли что-то вроде ключевого слова pass или yield в erlang?

Ответы [ 6 ]

11 голосов
/ 15 июля 2009

ОК, сначала определите функцию:

printEven(I,N) when I >= N -> ok;
printEven(I,N)             -> 
   if
    I rem 2 == 0 -> io:format("~p~n",[I]), printEven(I+1,N);
    I rem 2 == 1 -> printEven(I+1,N)
  end.

Erlang - это функциональный язык программирования, и (по определению) функции «имеют» значение, поэтому вы получите «что-то» обратно. По соглашению, после завершения функции, которую вы используете для побочных эффектов, вы получаете атом «ок», который лучше всего использовать здесь.

Вы можете «молча отказаться» от возвращаемого значения, если хотите. Вы делаете это, когда вызываете функцию путем сопоставления с шаблоном переменной «позаботиться» (которая подчеркивается):

_ = printEven(3,9),

или путем вызова функции без сопоставления с образцом:

printEven(3,9),

Тем не менее, гораздо лучше всегда проверять возвращаемые значения путем сопоставления с образцом при вызове функции:

ok = printEven(3,9),

Это действительно хорошая привычка, потому что вы будете использовать множество библиотечных функций, которые возвращают коды ошибок, как вы можете видеть из их спецификаций:

@spec funky(X) -> [ok | {error, bad_op} | {error, wig_out}]

Если у funky есть побочные эффекты, вы хотите знать, что он потерпел неудачу сейчас , вызвав его с сопоставлением с шаблоном, чтобы он потерпел крах здесь и сейчас, если funky завершится неудачей:

ok = funky(99),

Если вы сопоставите его с '_' или проигнорируете возвращаемое значение, оно вылетит через 268 строк, когда ваш моджо ожидает, что фанки выполнил его, и тогда это будет много труднее найти.

Это счастливое программирование пути, которое сделано в Erlang. «Пусть разбится» - это девиз. Если вы новичок в Erlang, вы обнаружите, что это очень смущает - как ходить по голому. Не волнуйтесь, обнимите это, это хорошо. Это приводит к тому, что много кода «не пишется».

(Вы должны также привыкнуть помещать предложение, заканчивающее рекурсию, в верхнее предложение, как показано здесь - это делает чтение кода sooo намного проще, когда у вас есть функция с несколькими предложениями.)

4 голосов
/ 14 июля 2009

просто верните атом.

printEven (I, N) -> готово.

должен это сделать.

2 голосов
/ 14 июля 2009

Вы также можете объединить тест даже в пункте охраны. Я также предпочитаю трюк готового атома - он показывает в вашем коде, что это предложение функции остановит «рекурсию».

printEven(I, N) when I<N, I rem 2 == 0 ->
    io:format("~p is even~n", [I]),
    printEven(I+1, N);
printEven(I,N) when I<N ->
    printEven(I+1, N);
printEven(I,N) ->
    done.
1 голос
/ 14 июля 2009

Я считаю, что ключевое слово "ok"

0 голосов
/ 29 декабря 2016

Это будет сделано:

printEven(I,N) -> ok.
0 голосов
/ 24 сентября 2015
printEven(Start, Stop) when Start =< Stop ->
    case Start rem 2 of
        0 -> io:format("~p~n", [Start]);  %returns ok
        _ -> do_nothing
    end,  
    printEven(Start+1, Stop);
printEven(Start, Stop) when Start > Stop ->
    ok.

Значением оператора case является либо ok, либо do_nothing, но оператор case не является последним выражением, поэтому его значение не будет возвращаемым значением для первого предложения функции, и поскольку значение выражения case не привязаны к переменной, значение просто отбрасывается.

Последнее выражение в первом предложении функции на самом деле printEven(Start+1, Stop), и этот вызов функции в конечном итоге вернет ok, как только рекурсия достигнет конца последовательности и выполнит printEven(Start, Stop) when Start > Stop -> ok;

printEven(1, 3) => ?
                   | 
                   V
             printEven(2, 3) => ?
                                | --side effect: output 2
                                V
                         printEven(3, 3) => ?
                                            |
                                            V 
                                      printEven(4, 3) => ok 

Заполнение возвращаемого значения для каждого вызова функции в цепочке дает:

printEven(1, 3) =>  ok
                    ^ 
                    |
              printEven(2, 3) => ok
                                 ^ 
                                 |
                         printEven(3, 3) => ok
                                            ^
                                            |
                                      printEven(4, 3) => ok 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...