【问题标题】:When to prefer `and` over `andalso` in guard tests在警戒测试中何时更喜欢 `and` 而不是 `andalso`
【发布时间】:2011-08-26 21:03:01
【问题描述】:

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

由于我称自己为“C 原生”,我看不出短路布尔求值的任何缺点。

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

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

【问题讨论】:

    标签: erlang short-circuiting boolean-expression


    【解决方案1】:

    探究过去:

    • 最初在守卫中只有, 分隔的测试,这些测试从左到右进行评估,直到没有更多并且守卫成功或测试失败并且守卫整体失败。后来添加了; 以允许在同一子句中使用备用守卫。如果警卫在测试之前评估, 的两侧,那么有人在此过程中弄错了。 @Kay 的例子似乎暗示他们确实应该从左到右。

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

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

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

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

    所以andandalso 都有自己的位置。

    【讨论】:

      【解决方案2】:

      Adam Lindbergs link 是对的。使用逗号确实比使用 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 之间存在优化步骤。

      【讨论】:

        【解决方案3】:

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

        【讨论】:

          【解决方案4】:

          布尔运算符“and”和“or”始终评估运算符双方的争论。而如果您想要 C 运算符 &&|| 的功能(其中只有在需要时才评估第二个参数..例如,如果我们想要评估 "true orelse false" 一旦发现 true 是第一个论点,第二个论点将不会被评估,如果使用了 "or" 则不是这种情况) go for "andalso”和“orelse”。

          【讨论】:

            猜你喜欢
            • 2017-10-13
            • 2010-09-24
            • 2010-09-20
            • 1970-01-01
            • 2015-09-03
            • 1970-01-01
            • 2022-01-03
            • 2016-09-24
            • 2011-05-13
            相关资源
            最近更新 更多