tuplas then else delete atom erlang short-circuiting boolean-expression

then - p erlang



Cuándo preferir `y` sobre` andalso` en las pruebas de guardia (4)

Tengo curiosidad de por qué la coma ‹,› es un atajo para y no también en las pruebas de guardia.

Como me llamaría "C nativo", no veo ninguna deficiencia en la evaluación booleana de corto circuito.

to_core algunos códigos de prueba usando la to_core para ver qué código se genera realmente. Al usar la coma, veo que el valor de la mano izquierda y el derecho y el valor se evalúan y ambos son editados. Con andalso tiene un bloque de caso dentro del bloque de caso y no se llama a erlang:and/2 .

No hice pruebas comparativas, pero me atrevería a decir que la variante andalso es la más rápida.


El link Adam Lindberg es correcto. Usar la coma genera un código de haz mejor que usar andalso. Compilé el siguiente código usando la marca + 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.

que genera

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

Solo observé lo que se genera con la marca + to_core, pero obviamente hay un paso de optimización entre to_core y to_asm.


Es una razón histórica. and se implementó antes andalso , que se introdujo en Erlang 5.1 (la única referencia que puedo encontrar en este momento es link ). Los guardias no se han cambiado debido a la compatibilidad con versiones anteriores.


Los operadores booleanos " y " y " o " siempre evalúan los argumentos en ambos lados del operador. Considerando que si quieres la funcionalidad de los operadores de C && y || (donde el segundo argumento se evalúa solo si es necesario ... por ejemplo, si queremos evaluar "verdadero o falso falso" tan pronto como se encuentre que el primer argumento es verdadero, el segundo argumento no se evaluará, lo que no es el caso " o "sido usado) ir para" andalso "y" orelse ".


Para profundizar en el pasado:

  • Originalmente en las guardias solo había pruebas separadas que se evaluaron de izquierda a derecha hasta que no hubo más y la guardia tuvo éxito o una prueba falló y la guardia en su totalidad falló. Despues Se agregó para permitir guardias alternativos en la misma cláusula. Si los guardias evalúan ambos lados de una , antes de la prueba, alguien se ha equivocado en el camino. El ejemplo de @ Kay parece implicar que van de izquierda a derecha como deberían.

  • Los operadores booleanos solo fueron permitidos mucho más tarde en la guardia.

  • and , junto con or , xor y not , es un operador booleano y no fue pensado para el control. Todos son estrictos y primero evalúan sus argumentos, como los operadores aritméticos + , - , * y ''/''. También existen operadores booleanos estrictos en C.

  • Los operadores de control de cortocircuito, orelse y orelse se agregaron más tarde para simplificar algunos códigos. Como ha dicho, el compilador las expande a expresiones de case anidadas, por lo que no hay una mejora en el rendimiento al usarlas, solo la conveniencia y la claridad del código. Esto explicaría el código resultante que viste.

  • NB en guardias hay pruebas y no expresiones. Hay una diferencia sutil que significa que si bien usar y andalso es equivalente a , usar orelse no es equivalente a ; . Esto se deja a otra pregunta. Pista: se trata del fracaso.

Así que ambos and andalso tienen su lugar.