31

我很好奇为什么逗号‹,›是守卫测试的快捷方式and而不是andalso守卫测试。

由于我称自己为“C 本地人”,因此我看不到短路布尔评估的任何缺点。

我使用该标志编译了一些测试代码,to_core以查看实际生成的代码。使用逗号,我看到左手值和右值和值被评估并且两者都被评估。你在andalsocase 块中有一个 case 块,并且没有调用erlang:and/2.

我没有进行基准测试,但我敢说该andalso变体是更快的变体。

4

4 回答 4

29

深入研究过去:

  • 最初在守卫中只有,单独的测试,从左到右评估,直到没有更多的测试并且守卫成功,或者测试失败并且整个守卫失败。后来;被添加以允许在同一条款中使用备用警卫。如果警卫在测试之前评估了 a 的双方,,那么有人在此过程中弄错了。@Kay 的例子似乎暗示他们确实应该从左到右。

  • 布尔运算符仅在很晚才允许在警卫中使用。

  • andor,xor和,一起not是布尔运算符,不用于控制。它们都是严格的,并首先评估它们的参数,例如算术运算符+、和 '/'。C 中也存在严格的布尔运算符。-*

  • 短路控制运算符andalsoorelse后来被添加以简化一些代码。正如您所说,编译器确实将它们扩展为嵌套case表达式,因此使用它们没有性能提升,只是代码的方便和清晰。这将解释您看到的结果代码。

  • 注意守卫中有测试而不是表达式。有一个细微的区别,这意味着在使用时andandalso等价于,使用orelse不等价于;。这留给另一个问题。提示:这都是关于失败的。

所以两者and都有andalso自己的位置。

于 2011-05-17T15:52:53.093 回答
8

Adam Lindbergs的链接是正确的。使用逗号确实比使用 andalso 生成更好的光束代码。我使用 +to_asm 标志编译了以下代码:

a(A,B) ->
    case ok of
        _ when A, B -> true;
        _ -> false
    end.
aa(A,B) ->
    case ok of
        _ when A andalso B -> true;
        _ -> false
    end.

这会产生

{function, a, 2, 2}.
  {label,1}.
    {func_info,{atom,andAndAndalso},{atom,a},2}.
  {label,2}.
    {test,is_eq_exact,{f,3},[{x,0},{atom,true}]}.
    {test,is_eq_exact,{f,3},[{x,1},{atom,true}]}.
    {move,{atom,true},{x,0}}.
    return.
  {label,3}.
    {move,{atom,false},{x,0}}.
    return.

{function, aa, 2, 5}.
  {label,4}.
    {func_info,{atom,andAndAndalso},{atom,aa},2}.
  {label,5}.
    {test,is_atom,{f,7},[{x,0}]}.
    {select_val,{x,0},{f,7},{list,[{atom,true},{f,6},{atom,false},{f,9}]}}.
  {label,6}.
    {move,{x,1},{x,2}}.
    {jump,{f,8}}.
  {label,7}.
    {move,{x,0},{x,2}}.
  {label,8}.
    {test,is_eq_exact,{f,9},[{x,2},{atom,true}]}.
    {move,{atom,true},{x,0}}.
    return.
  {label,9}.
    {move,{atom,false},{x,0}}.
    return.

我只查看了使用 +to_core 标志生成的内容,但显然在 to_core 和 to_asm 之间存在优化步骤。

于 2011-05-17T10:02:50.917 回答
5

这是历史原因。and之前实现过andalso,它是在 Erlang 5.1 中引入的(我现在能找到的唯一参考是EEP-17)。由于向后兼容,Guards 没有改变。

于 2011-05-17T08:08:46.587 回答
5

The boolean operators "and" and "or" always evaluate arguements on both the sides of the operator. Whereas if you want the functionality of C operators && and || (where 2nd arguement is evaluated only if needed..for eg if we want to evalue "true orelse false" as soon as true is found to be the first arguement, the second arguement will not be evaluated which is not the case had "or" been used ) go for "andalso" and "orelse".

于 2011-05-21T14:31:29.887 回答