什么时候在守卫测试中更喜欢`和`而不是`andalso`

kay*_*kay 24 erlang boolean-expression short-circuiting

我很好奇为什么逗号<,>是一个快捷方式and而不是andalso保护测试.

由于我称自己为"C native",我没有看到短路布尔评估的任何缺点.

我使用to_core标志编译了一些测试代码,以查看实际生成的代码.使用逗号,我看到左手值,右边和值得到评估,并且两者都是和.随着andalso你的情况下块内的情况下块,并没有呼叫erlang:and/2.

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

rvi*_*ing 25

深入研究过去:

  • 最初在守卫中只有,分开的测试,这些测试是从左到右进行评估,直到没有更多,防守成功或测试失败,整个防守失败.后来;被添加以允许同一条款中的替代警卫.如果警卫,在测试之前对两侧进行了评估,那么有人在此过程中会遇到错误.@Kay的例子似乎暗示他们确实应该从左到右.

  • 布尔运算符只允许在守卫中使用很久.

  • and,with or,xornot,是一个布尔运算符,不用于控制.他们都是严格的,并首先评估自己的论点,像算术运算符+,-,*和"/".C中也存在严格的布尔运算符.

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

  • 在警卫中注意测试,而不是表达.有一个微妙的区别,这意味着虽然使用andandalso相当于,使用orelse不等同;.这留给另一个问题.提示:这都是关于失败的.

因此,无论and并且andalso有自己的位置.


kay*_*kay 7

Adam Lindbergs 链接是对的.使用逗号确实生成比使用和更好的波束代码.我使用+ 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.
Run Code Online (Sandbox Code Playgroud)

产生

{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.
Run Code Online (Sandbox Code Playgroud)

我只研究了使用+ to_core标志生成的内容,但显然在to_core和to_asm之间有一个优化步骤.


Ada*_*erg 5

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


nit*_*112 5

布尔运算符“”和“”总是评估运算符两侧的参数。而如果您想要 C 运算符&&|| 的功能 (仅在需要时才评估第二个论点......例如,如果我们想在发现第一个论点为真时立即评估“真假”,则不会评估第二个论点,这不是这种情况““被使用)去” andalso “和”否则别指望”。