2012-01-10 16 views
6

En la mayoría de los lenguajes de programación, los argumentos pasados ​​a una función se evalúan antes de la función los usa, es decir, se evalúan con entusiasmo.¿Por qué la mayoría de los lenguajes de programación utilizan una evaluación entusiasta para los argumentos pasados ​​a una función?

Para mí, parece que tendría mucho más sentido evaluar los argumentos solo una vez que la función los usa, es decir, de forma perezosa. Esto tiene más sentido para mí porque parece que tendría un beneficio en el rendimiento: ¿por qué evaluar cosas que ni siquiera son necesarias?

Además, suponga que desea implementar una función de if que acepte un valor lógico, y un objeto para volver si el booleana es verdadera, y otro objeto para volver si el booleano es falso:

object if(bool condition, object valueIfTrue, object valueIfFalse) { 
    if(condition) return valueIfTrue; 
    return valueIfFalse; 
} 

En una lenguaje que evalúa con entusiasmo los argumentos, ambos objetos siempre se evalúan aunque la función siempre solo necesite uno de ellos, que, en el mejor de los casos, incurre en una ligera sobrecarga innecesaria y, en el peor de los casos, causa un ciclo infinito.

Dicho esto, dado que la mayoría de los lenguajes de programación utilizan una evaluación entusiasta de los argumentos de la función, supongo que debe haber una razón por la que generalmente se hace de esa manera. ¿Hay algún beneficio grande de la evaluación entusiasta que estoy pasando por alto, es simplemente porque era más fácil implementar los lenguajes de esa manera, es solo tradición, o qué?

+0

Porque es fácil compilar/interpretar código en esos lenguajes no perezosos. –

Respuesta

5

Hay un par de razones que he visto para la evaluación ansiosos, los cuales son importantes:

  1. evaluación Eager significa que los efectos secundarios ocurren inmediatamente y siempre.Si usa la evaluación diferida, no puede confiar en que los efectos secundarios de algo que haya hecho anteriormente hayan tenido efecto.
  2. La evaluación lenta trae consigo una cierta cantidad de hinchazón de la memoria. Por lo general, se necesita mucha menos memoria para almacenar el resultado de un cálculo que para almacenar el thunk que describe el cálculo. Esto puede llevar a utilizar demasiada memoria (es decir, compensaciones de tiempo vs. memoria) y, a veces más importante, un tiempo más difícil para descifrar las características de memoria del programa/algoritmo.

La evaluación diferida puede ser una herramienta poderosa, pero no sin sus costos. Los lenguajes puramente funcionales tienden a evitar el problema n. ° 1 porque no tienen efectos secundarios (en general), pero a veces son mordidos por el problema n. ° 2. Los lenguajes que permiten la evaluación diferida (las macros LISP son una forma de esto, aunque no lo mismo que la evaluación perezosa) pueden tener lo mejor de ambos mundos, pero a costa de un mayor esfuerzo por parte del programador.

3

Opción 1 - cargar todos me lo quitaron en los registros, la función de llamada

Opción 2 - cargar primer argumento, evaluar si es necesario, espere a que la tubería de la CPU para borrar, obtener siguiente argumento, evaluar si es necesario .... luego cargue los parámetros necesarios en los registros, ejecute la función con lógica adicional para marcar qué registros están en uso.

Un 'si' ya va a causar un atraco el rendimiento de todos modos mientras espera para ver qué ruta de código se está ejecutando (ligeramente salvo por la predicción de saltos)

3

Para que la evaluación perezosa para trabajar es necesario que haya código adicional y datos en algún lugar para realizar un seguimiento de si una expresión ha sido evaluada. En algunos casos, esto sería más costoso que una evaluación entusiasta. Determinar si una expresión puede beneficiarse de una evaluación perezosa puede requerir un conocimiento de alto nivel sobre cómo funciona el programa; el compilador y/o intérprete ciertamente no tendrá este tipo de conocimiento.

Además, si la función o expresión tiene efectos secundarios, la estrategia de evaluación diferida puede hacer que los programas se comporten de manera que no sean intuitivos y difíciles de depurar. Esto, por supuesto, no es un problema en los lenguajes de programación funcionales donde no hay efectos secundarios por diseño. De hecho, la evaluación diferida es la estrategia predeterminada para la mayoría de los lenguajes de programación funcionales, si no para todos.

Dicho esto, no hay nada que le impida utilizar ambas estrategias en diferentes lugares. No me sorprendería si se utiliza un enfoque híbrido en programas no triviales.

2

Aparte de las excelentes respuestas ya proporcionadas, hay otro problema práctico con la evaluación perezosa. Si tiene una cadena de expresiones que solo se evalúa de forma diferida cuando se utiliza la última, puede ser bastante difícil identificar cuellos de botella de rendimiento.

+0

¿Puedes dar un ejemplo? Estoy tratando de visualizar el tipo de código del que estás hablando. –

+0

Bueno, supongamos que tiene un argumento 'x' para una función que, cuando se evalúa, obtiene el valor de otra variable' y' y este tipo de cadena regresa. Puede haber algunas evaluaciones que son lentas y que son cuellos de botella, pero las verás cuando evalúes 'x'. Eso puede ser engañoso y el origen a veces difícil de rastrear. –

0

En el Período Cretácico, hubo una serie de idiomas que hicieron esto. SNOBOL, por ejemplo. ALGOL 68 tenía una capacidad de "llamar por nombre", que hizo algo como esto. Y C (así como sus muchos derivados) lo hace en una situación muy específica, que describe como "cortocircuito" de una expresión booleana. En general, casi siempre es una fuente de más confusión y errores que de poder habilitante.

+0

No creo que la llamada de Algol por su nombre fuera una evaluación perezosa, creo que fue por referencias en lugar de valores. –

+0

La llamada de ALGOL fue más una sustitución textual y explícitamente no una referencia, por lo que creo que califica como evaluación perezosa. Aunque ahora que lo pienso, podría haber sido ALGOL 60 que lo introdujo, no ALGOL 68. –

+1

Ahh ... la década de 1960, el "Período Cretácico" (http://stackoverflow.com/questions/1463321/was -algol-ever-used-for-mainstream-programming) "cuando éramos gigantes y andábamos en la luna ... :-) Algol60 tiene una llamada por su nombre. Algol68 no tiene llamada por nombre, sin embargo, 68 tiene llamada por referencia. Y además, ... la evaluación perezosa puede ser implementada en un programa por el codificador usando "procediendo", c.f. [Evaluación de cortocircuito usando procedimientos] (http://stackoverflow.com/questions/9462051/short-circuit-evaluation-using-procedures) – NevilleDNZ

Cuestiones relacionadas