【问题标题】:Why does Erlang if statement support only specific functions in its guard?为什么 Erlang if 语句只支持其保护中的特定功能?
【发布时间】:2021-03-13 11:57:07
【问题描述】:

为什么 Erlang if 语句只支持其保护中的特定功能?

即-

ok(A) ->
  if
    whereis(abc)=:=undefined ->
            register(abc,A);
    true -> exit(already_registered)
  end.

在这种情况下,我们会收到“非法守卫”错误。

使用函数的返回值作为条件的最佳做法是什么?

【问题讨论】:

  • 我总是更喜欢case 而不是if

标签: erlang


【解决方案1】:

检查这个问题:About the usage of "if" in Erlang language

简而言之:

保护序列中只允许有限数量的函数,而 whereis 不是其中之一

请改用case

【讨论】:

    【解决方案2】:

    来自其他编程语言,Erlang 的 if 似乎有奇怪的限制性,事实上,使用的并不多,大多数人选择使用 case。两者的区别在于case 可以测试任何表达式,而if 只能使用有效的Guard Expressions

    如上述链接中所述,Guard Expressions 仅限于保证没有副作用的已知函数。造成这种情况的原因有很多,其中大部分归结为代码的可预测性和可检查性。例如,由于匹配是自上而下进行的,所以不匹配的保护表达式将被执行,直到找到匹配的表达式。如果这些表达式有副作用,则很容易在调试过程中导致不可预测和令人困惑的结果。虽然您仍然可以使用 case 表达式完成此操作,但如果您看到 if,您可以知道测试中没有引入任何副作用,而无需检查。

    最后但重要的一点是,守卫必须终止。如果他们不这样做,函数调用的缩减可能会永远持续下去,并且由于调度程序是基于缩减的,这确实会非常糟糕,当事情变得糟糕时几乎没有什么可做的。

    作为一个反例,您可以正是出于这个原因使 Go 中的调度程序处于饥饿状态。因为 Go 的调度器(就像所有的微进程调度器一样)是协同多任务的,所以它必须等待一个 goroutine 让步,然后才能调度另一个 goroutine。就像在 Erlang 中一样,它会等待一个函数完成它当前正在执行的操作,然后才能继续。不同之处在于 Erlang 没有类似循环。为了完成循环,您需要递归,这需要函数调用/减少,并允许调度程序进行干预。在 Go 中,你有 C 风格的循环,它们不需要在它们的主体中调用函数,所以类似于 for { i = i+1 } 的代码会使调度程序挨饿。并不是说在它们的主体中没有函数调用的这种循环非常常见,但是这个问题确实存在。

    相反,在 Erlang 中,如果不明确地做这样的事情是非常困难的。但是如果守卫包含没有终止的代码,它就会变得微不足道。

    【讨论】:

    • " 如果您看到“如果”,则无需检查即可知道测试中没有引入副作用。 ——你说的副作用是什么意思? , 测试?表示测试/保护条件?
    • 意味着由保护子句调用的函数是“纯的”,或者换句话说,它可以通过逻辑替换它评估的内容,而不会改变程序的运行方式。副作用诱导函数是诸如“!”之类的东西。运算符,写入文件系统等。
    猜你喜欢
    • 2017-08-26
    • 2021-05-26
    • 1970-01-01
    • 2014-03-10
    • 2014-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多