在防护测试中何时更喜欢使用“and”而不是“andalso”

发布于 2024-11-08 00:12:44 字数 344 浏览 6 评论 0原文

我很好奇为什么在防护测试中逗号 <,> 是 and 的快捷方式,而不是 andalso

由于我称自己为“C 本地人”,所以我看不到短路布尔求值的任何缺点。

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

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

I am curious why the comma ‹,› is a shortcut for and and not andalso in guard tests.

Since I'd call myself a “C native” I fail to see any shortcomings of short-circuit boolean evaluation.

I compiled some test code using the to_core flag to see what code is actually generated. Using the comma, I see the left hand value and right and value get evaluated and both and'ed. With andalso you have a case block within the case block and no call to erlang:and/2.

I did no benchmark tests but I daresay the andalso variant is the faster one.

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

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

发布评论

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

评论(5

梦毁影碎の 2024-11-15 00:12:44

深入研究过去:

  • 最初在守卫中只有分隔的测试,这些测试从左到右进行评估,直到没有更多的和守卫成功或测试失败并且整个警卫失败。后来添加了 ; 以允许在同一子句中替代守卫。如果警卫在测试之前评估 , 的两侧,那么有人在整个过程中就犯了错误。 @Kay 的示例似乎暗示它们确实按照应有的方式从左到右进行。

  • 布尔运算符只在很晚的时候才被允许出现在守卫中。

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

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

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

所以 andandalso 都有自己的位置。

To delve into the past:

  • Originally in guards there were only , separated tests which were evaluated from left-to-right until either there were no more and the guard succeeded or a test failed and the guard as a whole failed. Later ; was added to allow alternate guards in the same clause. If guards evaluate both sides of a , before testing then someone has gotten it wrong along the way. @Kay's example seems to imply that they do go from left-to-right as they should.

  • Boolean operators were only allowed much later in guards.

  • and, together with or, xor and not, is a boolean operator and was not intended for control. They are all strict and evaluate their arguments first, like the arithmetic operators +, -, * and '/'. There exist strict boolean operators in C as well.

  • The short-circuiting control operators andalso and orelse were added later to simplify some code. As you have said the compiler does expand them to nested case expressions so there is no performance gain in using them, just convenience and clarity of code. This would explain the resultant code you saw.

  • N.B. in guards there are tests and not expressions. There is a subtle difference which means that while using and and andalso is equivalent to , using orelse is not equivalent to ;. This is left to another question. Hint: it's all about failure.

So both and and andalso have their place.

羁〃客ぐ 2024-11-15 00:12:44

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 之间有一个优化步骤。

Adam Lindbergs link is right. Using the comma does generate better beam code than using andalso. I compiled the following code using the +to_asm flag:

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.

which generates

{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.

I only looked into what is generated with the +to_core flag, but obviously there is a optimization step between to_core and to_asm.

血之狂魔 2024-11-15 00:12:44

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

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

┈┾☆殇 2024-11-15 00:12:44

这是有历史原因的。 and 是在 andalso 之前实现的,后者是在 Erlang 5.1 中引入的(我现在能找到的唯一参考是 EEP-17)。由于向后兼容性,守卫尚未更改。

It's an historical reason. and was implemented before andalso, which was introduced in Erlang 5.1 (the only reference I can find right now is EEP-17). Guards have not been changed because of backwards compatibility.

从﹋此江山别 2024-11-15 00:12:44

何时优先使用 andalso 而不是 and

在某些情况下,我们不希望对第二个表达式求值,例如

L1 = [1, 2, 3].
L2 = [1, 2, 3, 4].
Compare = fun(X, Y) -> X =:= Y end.
Accumulate = fun(X, Acc) -> X and Acc end.
(length(L1) =:= length(L2)) andalso 
  (lists:foldl(Accumulate, true, lists:zipwith(Compare, L1, L2))).

输出:

false

由于 zipwith 期望两个列表的长度相等,如果我们在这里使用 and,第二个表达式(其中包含 zipwith 在两个长度不等的列表上的应用) 也将被评估,导致异常。为了解决这种情况,我们可以使用 andalso 来防止计算第二个表达式。

When to prefer andalso over and:

There can be situations when we do not want the second expression to be evaluated e.g.

L1 = [1, 2, 3].
L2 = [1, 2, 3, 4].
Compare = fun(X, Y) -> X =:= Y end.
Accumulate = fun(X, Acc) -> X and Acc end.
(length(L1) =:= length(L2)) andalso 
  (lists:foldl(Accumulate, true, lists:zipwith(Compare, L1, L2))).

Output:

false

Since zipwith expects both lists to be of equal length, if we use and here, the second expression (which contains the application of zipwith on two lists of unequal lengths) will also be evaluated, resulting in an exception. To get round this type of situation, we can use andalso to prevent the second expression from being evaluated.

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