在Erlang中,有没有办法创建一个空函数?

发布于 2024-07-27 03:49:57 字数 423 浏览 4 评论 0原文

我正在编写一个 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").

我真的很想让最后一个案例自动退出,而不必在函数中打印任何内容。 我尝试删除它,但是由于递归完成后会抛出错误,因此会发生错误。

我怎样才能做到这一点? erlang 中有类似“pass”或“yield”关键字的东西吗?

I'm writing an Erlang function which prints every even number up to a given parameter.

So far, I've written the function with guards like this:

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").

I'd really like to have the last case just exit automatically and not have to print anything in the function. I've tried just removing it, but then an error occurs since when the recursion is done, an error is thrown.

How can I do this? Is there something like a 'pass' or 'yield' keyword in erlang?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

从来不烧饼 2024-08-03 03:49:58

我相信关键字是“ok

I believe the keyword is "ok"

毁梦 2024-08-03 03:49:58
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 语句的值可以是 okdo_nothing,但 case 语句不是最后一个表达式,因此它的值不会是第一个子句的返回值函数,并且由于 case 表达式的值未绑定到变量,因此该值将被简单地丢弃。

第一个函数子句中的最后一个表达式实际上是 printEven(Start+1, Stop),一旦递归到达末尾,该函数调用最终将返回 ok序列并在 Start > 时执行 printEven(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 
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.

The value of the case statement is either ok or do_nothing, but the case statement is not the last expression, so it's value will not be the return value for the first clause of the function, and because the value of the case expression is not bound to a variable, the value is simply discarded.

The last expression in the first function clause is actually printEven(Start+1, Stop), and that function call will end up returning ok once the recursion reaches the end of the sequence and executes 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 

Filling in the return value for each function call up the chain gives:

printEven(1, 3) =>  ok
                    ^ 
                    |
              printEven(2, 3) => ok
                                 ^ 
                                 |
                         printEven(3, 3) => ok
                                            ^
                                            |
                                      printEven(4, 3) => ok 
小糖芽 2024-08-03 03:49:58

这样就可以做到:

printEven(I,N) -> ok.

This would do it:

printEven(I,N) -> ok.
注定孤独终老 2024-08-03 03:49:57

好的,首先定义函数:

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 是一种函数式编程语言,并且(根据定义)函数“具有”一个值,因此您将得到“某些东西”。 按照惯例,在完成用于副作用的函数后返回的结果是原子“ok”,这是这里最好使用的。

如果需要,您可以“默默地丢弃”返回值。 当您通过与“不关心”变量(下划线)进行模式匹配来调用函数时,

_ = printEven(3,9),

或者通过在没有模式匹配的情况下调用函数来调用函数时,您可以这样做:

printEven(3,9),

但是,最好始终通过模式匹配来检查返回值当你调用函数时:

ok = printEven(3,9),

这是一个非常好的习惯,因为你将使用很多返回错误代码的库函数,正如你可以从它们的规范中看到的:

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

如果 funky 有副作用,你想知道它失败了 < strong>now 通过使用模式匹配调用它,这样如果 funky 失败,它就会立即崩溃:

ok = funky(99),

如果将其与 '_' 匹配或忽略返回值,当你的魔力期望 funky 完成他的工作时,它会在 268 行后崩溃,然后就很难找到了。

这就是快乐路径编程,这是 Erlang 中完成的事情。 “让它崩溃”是座右铭。 如果你是 Erlang 新手,你会发现这非常令人不安——就像赤身裸体走来走去。 别担心,拥抱它,这是一件好事。 它导致大量代码“未被编写”。

(您还应该养成将结束递归的子句作为顶部子句的习惯,如下所示 - 当您有一个多子句函数。)

OK, first define the function:

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 is a functional programming language and (by definition) functions 'have' a value so you are going to get 'something' back. By convention the thing you get back on completion of a function that you are using for side-effects is the atom 'ok', that's the best to use here.

You can 'silently discard' the return value if you want. You do that when you invoke the function by pattern matching to the 'don't care' variable (which is underscore):

_ = printEven(3,9),

or by calling the function without a pattern match:

printEven(3,9),

However, you are much better to always check return values by pattern matching when you invoke a function:

ok = printEven(3,9),

This is a a really good habit to get into because you will be using a lot of library functions that return error codes as you can see from their specs:

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

If funky has side effects you want to know it has failed now by invoking it with a pattern match so it will crash here and now if funky fails:

ok = funky(99),

If you match it to '_' or ignore the return value it will crash 268 lines later when your mojo expects funky to have done his thang, and then it is much harder to find.

This is happy path programming which is the done thing in Erlang. "Let it crash" is the motto. If you are new to Erlang you will find this very disconcerting - like walking about naked. Don't worry embrace it, it is a good thing. It leads to lots of code 'not being written'.

(You should also get in the habit of putting the clause that ends the recursion as the top clause as shown here - it makes reading the code sooo much easier when you have a multi-clause function.)

枫林﹌晚霞¤ 2024-08-03 03:49:57

只需返回一个原子。

printEven(I,N) ->; printEven(I,N) -> 完毕。

应该这样做。

just return an atom.

printEven(I,N) -> done.

should do it.

痴情 2024-08-03 03:49:57

您还可以在保护子句中合并对 Even 的测试。 我也更喜欢完成原子技巧 - 它在您的代码中显示它将停止“递归”的函数子句。

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.

You could also combine the test for even in the guard clause. I also prefer the done atom trick - it shows in your code that it's the function clause that will stop the "recursion".

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.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文