stringtranslate.com

Estrategia de evaluación

En un lenguaje de programación , una estrategia de evaluación es un conjunto de reglas para evaluar expresiones. [1] El término se usa a menudo para referirse a la noción más específica de una estrategia de paso de parámetros [2] que define el tipo de valor que se pasa a la función para cada parámetro (la estrategia de enlace ) [3] y si evaluar los parámetros de una llamada a función y, de ser así, en qué orden (el orden de evaluación ). [4] La noción de estrategia de reducción es distinta, [5] aunque algunos autores combinan los dos términos y la definición de cada término no existe un consenso generalizado. [6]

Para ilustrar, ejecutar una llamada de función f(a,b)puede primero evaluar los argumentos ay balmacenar los resultados en referencias o ubicaciones de memoria ref_ay ref_bluego evaluar el cuerpo de la función con esas referencias pasadas. Esto le da a la función la capacidad de buscar los valores de los argumentos y modificarlos. ellos mediante asignación como si fueran variables locales, y devolver valores a través de las referencias. Esta es la estrategia de evaluación de llamada por referencia. [7]

La estrategia de evaluación es parte de la semántica de la definición del lenguaje de programación. Algunos lenguajes, como PureScript , tienen variantes con diferentes estrategias de evaluación. Algunos lenguajes declarativos , como Datalog , admiten múltiples estrategias de evaluación. Algunos idiomas definen una convención de llamada . [ se necesita aclaración ]

Mesa

Esta es una tabla de estrategias de evaluación y idiomas representativos por año de introducción. Los idiomas representativos se enumeran en orden cronológico, comenzando con el idioma que introdujo la estrategia y seguido por los idiomas destacados que utilizan la estrategia. [8] : 434 

Órdenes de evaluación

Mientras que el orden de las operaciones define el árbol de sintaxis abstracta de la expresión, el orden de evaluación define el orden en el que se evalúan las expresiones. Por ejemplo, el programa Python

def  f ( x ):  imprimir ( x ,  fin = '' )  devolver  ximprimir ( f ( 1 )  +  f ( 2 ), fin = '' )

resultados 123debido al orden de evaluación de izquierda a derecha de Python, pero un programa similar en OCaml :

let  f  x  =  print_int  x ;  X  ;; print_int  ( f  1  +  f  2 )

salidas 213debido al orden de evaluación de derecha a izquierda de OCaml.

El orden de evaluación es principalmente visible en el código con efectos secundarios , pero también afecta el rendimiento del código porque un orden rígido inhibe la programación de instrucciones . Por esta razón, los estándares de lenguajes como C++ tradicionalmente dejaban el orden sin especificar, aunque lenguajes como Java y C# definen el orden de evaluación de izquierda a derecha [8] : 240–241  y el estándar C++17 ha agregado restricciones en el orden de evaluación. orden de evaluación. [21]

Evaluación estricta

El orden aplicativo es una familia de órdenes de evaluación en la que los argumentos de una función se evalúan completamente antes de aplicar la función.[22] Esto tiene el efecto de hacer que la función sea estricta , es decir, el resultado de la función no está definido si alguno de los argumentos no está definido, por lo que la evaluación del orden aplicativo se denomina más comúnmente evaluación estricta . Además, una llamada a una función se realiza tan pronto como se encuentra en un procedimiento, por lo que también se denomina evaluación ansiosa o evaluación codiciosa . [23] [24] Algunos autores se refieren a la evaluación estricta como "llamada por valor" debido a que la estrategia de vinculación de llamada por valor requiere una evaluación estricta. [4]

Common Lisp, Eiffel y Java evalúan los argumentos de las funciones de izquierda a derecha. C deja el orden indefinido. [25] El esquema requiere que el orden de ejecución sea la ejecución secuencial de una permutación no especificada de los argumentos. [26] De manera similar, OCaml deja el orden sin especificar, pero en la práctica evalúa los argumentos de derecha a izquierda debido al diseño de su máquina abstracta . [27] Todas estas son evaluaciones estrictas.

Evaluación no estricta

Un orden de evaluación no estricto es un orden de evaluación que no es estricto, es decir, una función puede devolver un resultado antes de que todos sus argumentos se evalúen por completo. [28] : 46–47  El ejemplo prototípico es la evaluación de orden normal , que no evalúa ninguno de los argumentos hasta que son necesarios en el cuerpo de la función. [29] La evaluación de orden normal tiene la propiedad de que termina sin error siempre que cualquier otra orden de evaluación hubiera terminado sin error. [30] El nombre "orden normal" proviene del cálculo lambda, donde la reducción de orden normal encontrará una forma normal si la hay (es una estrategia de reducción "normalizante" ). [31] La evaluación diferida se clasifica en este artículo como una técnica vinculante en lugar de un orden de evaluación. Pero esta distinción no siempre se sigue y algunos autores definen la evaluación perezosa como evaluación de orden normal o viceversa, [22] [32] o confunden la no rigurosidad con la evaluación perezosa. [28] : 43–44 

Las expresiones booleanas en muchos idiomas utilizan una forma de evaluación no estricta llamada evaluación de cortocircuito , donde la evaluación evalúa la expresión de la izquierda pero puede omitir la expresión de la derecha si se puede determinar el resultado; por ejemplo, en una expresión disyuntiva (OR) donde trueestá encontrado, o en una expresión conjuntiva (Y) donde falsese encuentra, y así sucesivamente. [32] Las expresiones condicionales utilizan de manera similar una evaluación no estricta: solo se evalúa una de las ramas. [28]

Comparación del orden aplicativo y la evaluación del orden normal.

Con la evaluación de orden normal, las expresiones que contienen un cálculo costoso, un error o un bucle infinito se ignorarán si no son necesarias, [4] permitiendo la especificación de construcciones de flujo de control definidas por el usuario, una función no disponible con la evaluación de orden aplicativa. La evaluación de orden normal utiliza estructuras complejas, como procesadores para expresiones no evaluadas, en comparación con la pila de llamadas utilizada en la evaluación de orden aplicativa. [33] Históricamente, la evaluación de órdenes normales ha carecido de herramientas de depuración utilizables debido a su complejidad. [34]

Estrategias vinculantes estrictas

Llamar por valor

Al llamar por valor (o pasar por valor), el valor evaluado de la expresión del argumento se vincula a la variable correspondiente en la función (frecuentemente copiando el valor en una nueva región de memoria). Si la función o procedimiento puede asignar valores a sus parámetros, solo se asigna su variable local; es decir, todo lo que se pasa a una llamada de función no cambia en el alcance de la persona que llama cuando la función regresa. Por ejemplo, en Pascal , pasar una matriz por valor hará que se copie toda la matriz y cualquier mutación en esta matriz será invisible para la persona que llama: [35]

programa principal ; utiliza crt ;  procedimiento PrintArray ( a : Matriz de números enteros ) ; var i : Entero ; comenzar para i : = Bajo ( a ) a Alto ( a ) Escribir ( a [ i ] ) ; EscribirLn () ; fin ;               Modificar procedimiento ( Fila : Matriz de números enteros ) ; comenzar PrintArray ( fila ) ; // 123 Fila [ 1 ] := 4 ; PrintArray ( fila ) ; // 143 fin ;              Var A : Matriz de números enteros ; comenzar A : = [ 1 , 2 , 3 ] ; Imprimirmatriz ( A ) ; // 123 Modificar ( A ) ; Imprimirmatriz ( A ) ; // 123 fin .              

Deriva semántica

Estrictamente hablando, bajo llamada por valor, ninguna operación realizada por la rutina llamada puede ser visible para quien llama, excepto como parte del valor de retorno. [16] Esto implica una forma de programación puramente funcional en la semántica de implementación. Sin embargo, el circunloquio "llamar por valor donde el valor es una referencia" se ha vuelto común, por ejemplo, en la comunidad Java. [36] En comparación con el paso por valor tradicional, el valor que se pasa no es un valor tal como se entiende en el significado ordinario de valor, como un número entero que puede escribirse como un literal, sino un identificador de referencia interno de la implementación . Las mutaciones en este identificador de referencia son visibles en la persona que llama. Debido a la mutación visible, esta forma de "llamada por valor" se denomina más propiamente llamada por compartir. [dieciséis]

En lenguajes puramente funcionales , los valores y las estructuras de datos son inmutables, por lo que una función no tiene posibilidad de modificar ninguno de sus argumentos. Como tal, normalmente no existe una diferencia semántica entre pasar por valor y pasar por referencia o un puntero a la estructura de datos, y las implementaciones frecuentemente usan llamada por referencia internamente para obtener beneficios de eficiencia. No obstante, estos lenguajes generalmente se describen como lenguajes de llamada por valor.

Llamar por referencia

Llamar por referencia (o pasar por referencia) es una estrategia de evaluación en la que un parámetro está vinculado a una referencia implícita a la variable utilizada como argumento, en lugar de una copia de su valor. Normalmente, esto significa que la función puede modificar (es decir, asignar a ) la variable utilizada como argumento, algo que será visto por quien la llama. Por lo tanto, la llamada por referencia se puede utilizar para proporcionar un canal adicional de comunicación entre la función llamada y la función que llama. Pasar por referencia puede mejorar significativamente el rendimiento: llamar a una función con una estructura de muchos megabytes como argumento no tiene que copiar la estructura grande, solo la referencia a la estructura (que generalmente es una palabra de máquina y solo unos pocos bytes). Sin embargo, un lenguaje de llamada por referencia hace que sea más difícil para un programador rastrear los efectos de una llamada a función y puede introducir errores sutiles.

Debido a la variación en la sintaxis, la diferencia entre llamada por referencia (donde el tipo de referencia es implícito) y llamada por uso compartido (donde el tipo de referencia es explícito) a menudo no está clara a primera vista. Una prueba de fuego simple es si es posible escribir una swap(a, b)función tradicional en el idioma. [36] Por ejemplo en Fortran:

programa Principal implícito ninguno entero :: a = 1 entero :: b = 2 llamada Intercambiar ( a , b ) imprimir * , a , b ! 2 1 contiene  subrutina Intercambio ( a , b ) entero , intención ( inout ) :: a , b entero :: temp temp = a a = b b = temp fin de subrutina Intercambio fin del programa Principal                                     

Por lo tanto, la intención de Fortran inoutimplementa la llamada por referencia; cualquier variable se puede convertir implícitamente en un identificador de referencia. Por el contrario, lo más cercano que se puede llegar en Java es:

clase  principal { cuadro de clase estática { valor int ; Caja pública ( valor int ) { this . valor = valor ; } } intercambio de vacío estático ( Caja a , Caja b ) { int temp = a . valor ; a . valor = b . valor ; b . valor = temperatura ; } public static void main ( String [] args ) { Cuadro a = nuevo Cuadro ( 1 ); Cuadro b = nuevo Cuadro ( 2 ); intercambiar ( a , b ); Sistema . afuera . println ( String . formato ( "%d %d" , a . valor , b . valor )); } } // salida: 2 1                                                        

donde Boxse debe utilizar un tipo explícito para introducir un identificador. Java es llamada por uso compartido pero no llamada por referencia. [36]

Llamar por copia-restauración

La llamada por copia-restauración, también conocida como "copia de entrada y salida", "llamada por resultado de valor", "llamada por retorno de valor" (como se denomina en la comunidad de Fortran ), es una variación de la llamada por referencia. Con la llamada mediante copia-restauración, el contenido del argumento se copia a una nueva variable local a la invocación de la llamada. Luego, la función puede modificar esta variable, de manera similar a la llamada por referencia, pero como la variable es local, las modificaciones no son visibles fuera de la invocación de la llamada durante la llamada. Cuando regresa la llamada a la función, el contenido actualizado de esta variable se copia nuevamente para sobrescribir el argumento original ("restaurado"). [37]

La semántica de la llamada mediante copia-restauración es similar en muchos casos a la llamada por referencia, pero difiere cuando dos o más argumentos de función se superponen entre sí (es decir, apuntan a la misma variable en el entorno de la persona que llama). En la llamada por referencia, escribir en un argumento afectará al otro durante la ejecución de la función. Bajo una llamada mediante copia-restauración, escribir en un argumento no afectará al otro durante la ejecución de la función, pero al final de la llamada, los valores de los dos argumentos pueden diferir y no está claro qué argumento se copia primero y, por lo tanto, qué valor recibe la variable de la persona que llama. [38] Por ejemplo, Ada especifica que la asignación de copia para cada parámetro in outo outse produce en un orden arbitrario. [39] En el siguiente programa (ilegal en Ada 2012) [40] se puede ver que el comportamiento de GNAT es copiar en orden de izquierda a derecha al regresar:

con  Ada.Text_IO ;  utilizar  Ada.Text_IO ;el procedimiento  Test_Copy_Restore  es  el procedimiento  Modificar  ( A ,  B  : in  out  Integer )  es  comenzar  A  :=  A  +  1 ;  segundo  :=  segundo  +  2 ;  finalizar  Modificar ;  X  :  Entero  :=  0 ; comenzar  Modificar ( X ,  X );  Put_Line ( "X = "  &  Integer ' Imagen ( X )); finalizar  Test_Copy_Restore ; -- $ gnatmake -gnatd.E test_copy_restore.adb; ./test_copy_restore -- test_copy_restore.adb:12:10: advertencia: el valor real grabable para "A" se superpone con el real para "B" [-gnatw.i] -- X = 2

Si el programa devolviera 1, estaría copiando de derecha a izquierda y, bajo llamada por semántica de referencia, el programa devolvería 3.

Cuando la referencia se pasa a la persona que llama sin inicializar (por ejemplo, un outparámetro en Ada en lugar de un in outparámetro), esta estrategia de evaluación puede denominarse "llamada por resultado".

Esta estrategia ha ganado atención en multiprocesamiento y llamadas a procedimientos remotos , [41] ya que, a diferencia de la llamada por referencia, no requiere comunicación frecuente entre subprocesos de ejecución para acceso a variables.

Llama compartiendo

La llamada compartiendo (también conocida como "pasar compartiendo", "llamada por objeto" o "llamada compartiendo objeto") es una estrategia de evaluación intermedia entre la llamada por valor y la llamada por referencia. En lugar de que cada variable se exponga como referencia, sólo una clase específica de valores, denominada "referencias", " tipos en caja " u "objetos", tienen semántica de referencia, y son las direcciones de estos punteros las que se pasan a la función. . Al igual que la llamada por valor, el valor de la dirección pasada es una copia, y la asignación directa al parámetro de la función sobrescribe la copia y no es visible para la función que llama. Al igual que la llamada por referencia, la mutación del objetivo del puntero es visible para la función que llama. Las mutaciones de un objeto mutable dentro de la función son visibles para la persona que llama porque el objeto no se copia ni se clona; se comparte , de ahí el nombre "llamar compartiendo". [dieciséis]

La técnica fue notada por primera vez por Barbara Liskov en 1974 para el lenguaje CLU . [16] Es utilizado por muchos lenguajes modernos como Python (los valores compartidos se denominan "objetos"), [42] Java (objetos), Ruby (objetos), JavaScript (objetos), Scheme (estructuras de datos como vectores) , [43] AppleScript (listas, registros, fechas y objetos de script), OCaml y ML (referencias, registros, matrices, objetos y otros tipos de datos compuestos), Maple (rtables y tablas) y Tcl (objetos). [44] El término "llamar compartiendo", tal como se utiliza en este artículo, no es de uso común; la terminología es inconsistente entre diferentes fuentes. Por ejemplo, en la comunidad Java, dicen que Java se llama por valor. [36]

Para objetos inmutables , no existe una diferencia real entre llamar por compartir y llamar por valor, excepto si la identidad del objeto es visible en el lenguaje. El uso de la llamada compartiendo con objetos mutables es una alternativa a los parámetros de entrada/salida : el parámetro no se asigna (el argumento no se sobrescribe y la identidad del objeto no se cambia), pero el objeto (argumento) se muta. [45]

Por ejemplo, en Python, las listas son mutables y se pasan mediante llamada mediante uso compartido, por lo que:

def  f ( una_lista ):  una_lista . añadir ( 1 )m  =  [] f ( m ) imprimir ( m )

produce [1]porque el appendmétodo modifica el objeto en el que se llama.

Por el contrario, las asignaciones dentro de una función no son perceptibles para quien llama. Por ejemplo, este código vincula el argumento formal a un nuevo objeto, pero no es visible para la persona que llama porque no muta a_list:

def  f ( una_lista ):  una_lista  =  una_lista  +  [ 1 ]  print ( una_lista )  # [1]m  =  [] f ( m ) imprimir ( m )  # []

Llamar por dirección

Llamar por dirección , pasar por dirección o llamar/pasar por puntero es un método de paso de parámetros donde la dirección del argumento se pasa como parámetro formal. Dentro de la función, la dirección (puntero) se puede utilizar para acceder o modificar el valor del argumento. Por ejemplo, la operación de intercambio se puede implementar de la siguiente manera en C: [46]

#incluir <stdio.h> intercambio vacío ( int * a , int * b ) { int temp = * a ; * a = * b ; * b = temperatura ; }               int principal () { int a = 1 ; int b = 2 ; intercambiar ( &a , & b ); printf ( "%d %d" , a , b ); // 2 1 devuelve 0 ; }                  

Algunos autores lo tratan &como parte de la sintaxis de llamar swap. Desde este punto de vista, C admite la estrategia de paso de parámetros de llamada por referencia. [47] Otros autores tienen una opinión diferente de que la implementación presentada swapen C es solo una simulación de llamada por referencia utilizando punteros. [48] ​​Bajo esta visión de "simulación", las variables mutables en C no son de primera clase (es decir, los valores l no son expresiones), sino más bien los tipos de puntero. Desde este punto de vista, el programa de intercambio presentado es azúcar sintáctico para un programa que utiliza punteros en todo momento, [49] por ejemplo este programa ( ready assignse han agregado para resaltar las similitudes con el Boxprograma de llamada compartida de Java anterior):

#incluir <stdio.h> int leer ( int * p ) { retorno * p ; }     asignación nula ( int * p , int v ) { * p = v ; }        intercambio vacío ( int * a , int * b ) { int temp_storage ; int * temp = & temp_storage ; asignar ( temperatura , leer ( a )); asignar ( a , leer ( b )); asignar ( b , leer ( temp )); }                 int principal () { int un_almacenamiento ; int * a = & a_almacenamiento ; int b_almacenamiento ; int * b = & b_almacenamiento ; asignar ( a , 1 ); asignar ( b , 2 ); intercambiar ( a , b ); printf ( "%d %d" , leer ( a ), leer ( b )); // 2 1 devuelve 0 ; }                        

Debido a que en este programa swapopera con punteros y no puede cambiar los punteros en sí, sino solo los valores a los que apuntan, esta visión sostiene que la principal estrategia de evaluación de C es más similar a la llamada mediante uso compartido.

C++ confunde aún más el problema al permitir swapque se declare y utilice con una sintaxis de "referencia" muy ligera: [50]

intercambio vacío ( int & a , int & b ) { int temp = a ; a = b ; b = temperatura ; }               int principal () { int a = 1 ; int b = 2 ; intercambiar ( a , b ); std :: cout << a << b << std :: endl ; // 2 1 devuelve 0 ; }                      

Semánticamente, esto es equivalente a los ejemplos de C. Como tal, muchos autores consideran que la llamada por dirección es una estrategia única de paso de parámetros distinta de la llamada por valor, la llamada por referencia y la llamada por uso compartido.

Convocatoria por unificación

En programación lógica , la evaluación de una expresión puede corresponder simplemente a la unificación de los términos involucrados combinada con la aplicación de alguna forma de resolución . La unificación debe clasificarse como una estrategia vinculante estricta porque se lleva a cabo en su totalidad. Sin embargo, la unificación también se puede realizar en variables ilimitadas, por lo que es posible que las llamadas no necesariamente se comprometan con los valores finales de todas sus variables.

Estrategias vinculantes no estrictas

Llamar por nombre

La llamada por nombre es una estrategia de evaluación en la que los argumentos de una función no se evalúan antes de llamar a la función; más bien, se sustituyen directamente en el cuerpo de la función (mediante la sustitución que evita la captura ) y luego se dejan para que se evalúen cada vez que aparecen en el función. Si un argumento no se utiliza en el cuerpo de la función, el argumento nunca se evalúa; si se utiliza varias veces, se reevalúa cada vez que aparece. (Consulte el dispositivo de Jensen para conocer una técnica de programación que aprovecha esto).

En ocasiones, la evaluación de llamada por nombre es preferible a la evaluación de llamada por valor. Si el argumento de una función no se utiliza en la función, la llamada por nombre ahorrará tiempo al no evaluar el argumento, mientras que la llamada por valor lo evaluará independientemente. Si el argumento es un cálculo no final, la ventaja es enorme. Sin embargo, cuando se utiliza el argumento de función, la llamada por nombre suele ser más lenta y requiere un mecanismo como un procesador .

Los lenguajes .NET pueden simular llamadas por nombre utilizando delegados o Expression<T>parámetros. Esto último da como resultado que se le proporcione a la función un árbol de sintaxis abstracta . Eiffel proporciona agentes, que representan una operación que debe evaluarse cuando sea necesario. Seed7 proporciona llamadas por nombre con parámetros de función. Los programas Java pueden realizar una evaluación diferida similar utilizando expresiones lambda y la java.util.function.Supplier<T>interfaz.

llamar por necesidad

La llamada por necesidad es una variante memorizada de la llamada por nombre, donde, si se evalúa el argumento de la función, ese valor se almacena para su uso posterior. Si el argumento es puro (es decir, libre de efectos secundarios), esto produce los mismos resultados que llamar por nombre, ahorrando el costo de volver a calcular el argumento.

Haskell es un lenguaje muy conocido que utiliza la evaluación de llamada por necesidad. Debido a que la evaluación de expresiones puede ocurrir arbitrariamente en una etapa avanzada de un cálculo, Haskell solo admite efectos secundarios (como la mutación ) mediante el uso de mónadas . Esto elimina cualquier comportamiento inesperado de las variables cuyos valores cambian antes de su evaluación retrasada.

En la implementación de llamada por necesidad de R , se pasan todos los argumentos, lo que significa que R permite efectos secundarios arbitrarios.

La evaluación diferida es la implementación más común de la semántica de llamada por necesidad, pero existen variaciones como la evaluación optimista. Los lenguajes .NET implementan llamadas según necesidad usando el tipo Lazy<T>.

La reducción de gráficos es una implementación eficiente de la evaluación diferida.

Llamada por macro expansión

La llamada por expansión de macro es similar a la llamada por nombre, pero utiliza sustitución textual en lugar de sustitución que evita la captura . Por lo tanto, la macrosustitución puede resultar en una captura de variables, lo que lleva a errores y comportamientos no deseados. Las macros higiénicas evitan este problema al buscar y reemplazar variables sombreadas que no son parámetros.

Llamar por futuro

"Llamada por futuro", también conocida como "llamada paralela por nombre" o "evaluación indulgente", [51] es una estrategia de evaluación concurrente que combina una semántica no estricta con una evaluación entusiasta. El método requiere programación y sincronización dinámicas detalladas, pero es adecuado para máquinas masivamente paralelas.

La estrategia crea un futuro (promesa) para el cuerpo de la función y cada uno de sus argumentos. Estos futuros se calculan simultáneamente con el flujo del resto del programa. Cuando un futuro A requiere el valor de otro futuro B que aún no ha sido calculado, el futuro A se bloquea hasta que el futuro B termina de calcular y tiene un valor. Si el futuro B ya ha terminado de calcular, el valor se devuelve inmediatamente. Los condicionales se bloquean hasta que se evalúa su condición y las lambdas no crean futuros hasta que se aplican por completo. [52]

Si se implementa con procesos o subprocesos, la creación de un futuro generará uno o más procesos o subprocesos nuevos (para las promesas), acceder al valor los sincronizará con el subproceso principal y finalizar el cálculo del futuro corresponde a eliminar las promesas que calculan su valor. Si se implementa con una corrutina , como en .NET async/await , la creación de un futuro llama a una corrutina (una función asíncrona), que puede ceder a la persona que llama y, a su vez, devolverse cuando se usa el valor, realizando múltiples tareas de manera cooperativa.

La estrategia no es determinista, ya que la evaluación puede ocurrir en cualquier momento entre la creación del futuro (es decir, cuando se da la expresión) y el uso del valor del futuro. La estrategia no es estricta porque el cuerpo de la función puede devolver un valor antes de que se evalúen los argumentos. Sin embargo, en la mayoría de las implementaciones, la ejecución aún puede bloquearse al evaluar un argumento innecesario. Por ejemplo, el programa

f x = 1 / x g y = 1 principal = imprimir ( g ( f 0 ))           

puede tener gun final antes fy una salida 1, o puede generar un error debido a la evaluación 1/0. [28]

La llamada por futuro es similar a la llamada por necesidad en que los valores se calculan solo una vez. Con un manejo cuidadoso de los errores y la no terminación, en particular la terminación de futuros a la mitad si se determina que no serán necesarios, la llamada por futuro también tiene las mismas propiedades de terminación que la evaluación de llamada por necesidad. [52] Sin embargo, la llamada por futuro puede realizar un trabajo especulativo innecesario en comparación con la llamada por necesidad, como la evaluación profunda de una estructura de datos perezosa. [28] Esto se puede evitar utilizando futuros perezosos que no inician el cálculo hasta que esté seguro de que el valor es necesario.

Evaluación optimista

La evaluación optimista es una variante de llamada por necesidad en la que el argumento de la función se evalúa parcialmente en un estilo de llamada por valor durante un período de tiempo (que puede ajustarse en tiempo de ejecución ). Una vez transcurrido ese tiempo, se cancela la evaluación y se aplica la función mediante llamada por necesidad. [53] Este enfoque evita algunos de los gastos de tiempo de ejecución de las llamadas por necesidad manteniendo al mismo tiempo las características de terminación deseadas.

Ver también

Referencias

  1. ^ Araki, Shota; Nishizaki, Shin-ya (noviembre de 2014). "Evaluación de llamada por nombre de cálculos RPC y RMI". Teoría y práctica de la computación. pag. 1. doi :10.1142/9789814612883_0001. ISBN 978-981-4612-87-6. Consultado el 21 de agosto de 2021 .
  2. ^ Turbak, Franklyn; Gifford, David (18 de julio de 2008). Conceptos de diseño en lenguajes de programación. Prensa del MIT. pag. 309.ISBN 978-0-262-30315-6.
  3. ^ Manivela, Erik; Felleisen, Matías (1991). "Paso de parámetros y cálculo lambda". Actas del 18º simposio ACM SIGPLAN-SIGACT sobre principios de lenguajes de programación - POPL '91 . pag. 2. CiteSeerX 10.1.1.23.4385 . doi :10.1145/99583.99616. ISBN  0897914198. S2CID  5782416.
  4. ^ abc Wilhelm, Reinhard; Seidl, Helmut (10 de noviembre de 2010). Diseño de compiladores: máquinas virtuales. Medios de ciencia y negocios de Springer. pag. 61.ISBN 978-3-642-14909-2.
  5. ^ Nita, Stefanía Loredana; Mihailescu, Marius (2017). "Introducción". Haskell concurrente práctico . pag. 3. doi :10.1007/978-1-4842-2781-7_1. ISBN 978-1-4842-2780-0.
  6. ^ Pierce, Benjamín C. (2002). Tipos y lenguajes de programación. Prensa del MIT . pag. 56.ISBN 0-262-16209-1.
  7. ^ Daniel P. Friedman; Varita Mitchell (2008). Fundamentos de los lenguajes de programación (tercera ed.). Cambridge, MA: Prensa del MIT . ISBN 978-0262062794.
  8. ^ ab Scott, Michael Lee (2016). Pragmática del lenguaje de programación (Cuarta ed.). Waltham, MA: Elsevier. ISBN 9780124104778.
  9. ^ "Evite copias de datos innecesarias: MATLAB y Simulink". www.mathworks.com . Consultado el 28 de enero de 2023 .
  10. ^ Hasti, Rebeca. "Paso de parámetros". CS 536: Introducción a lenguajes de programación y compiladores . Universidad de Wisconsin . Consultado el 22 de agosto de 2021 .
  11. ^ JA Robinson (enero de 1965). "Una lógica orientada a máquinas basada en el principio de resolución". Revista de la ACM . 12 (1): 23–41. doi : 10.1145/321250.321253 . S2CID  14389185.; Aquí: sección 5.8, p.32
  12. ^ JA Robinson (1971). "Lógica computacional: el cálculo de unificación". Inteligencia de las máquinas . 6 : 63–72.
  13. ^ Bundy, Alan; Wallen, Lincoln (1984). "SASL". Catálogo de Herramientas de Inteligencia Artificial . pag. 117. doi :10.1007/978-3-642-96868-6_222. ISBN 978-3-540-13938-6. Probablemente fue el primer lenguaje que explotó sistemáticamente el poder de la evaluación perezosa.
  14. ^ Fay, Colin (30 de julio de 2018). "Acerca de la evaluación perezosa". Bloggers R. Consultado el 21 de agosto de 2021 .
  15. ^ Wadsworth, Christopher P. (1971). Semántica y Pragmática del Cálculo Lambda (Doctor). Universidad de Oxford.
  16. ^ abcde Liskov, Bárbara; Atkinson, Russ; Florece, Toby; musgo, Eliot; Schaffert, Craig; Scheifler, Craig; Snyder, Alan (octubre de 1979). "Manual de referencia de CLU" (PDF) . Laboratorio de Informática . Instituto de Tecnología de Massachusetts. págs. 14-15. Archivado (PDF) desde el original el 22 de septiembre de 2006 . Consultado el 19 de mayo de 2011 .
  17. ^ "PHP: Pasando por referencia - Manual". www.php.net . Consultado el 4 de julio de 2021 .
  18. ^ Wagner, Bill (12 de abril de 2023). "Pasar parámetros - Guía de programación de C#". Documentos de Microsoft . Consultado el 10 de septiembre de 2023 .
  19. ^ Dollard, Kathleen (15 de septiembre de 2021). "Pasar argumentos por valor y por referencia - Visual Basic". Documentos de Microsoft . Consultado el 10 de septiembre de 2023 .
  20. ^ ab "Historia de C++". es.cppreference.com . Consultado el 11 de junio de 2022 .
  21. ^ Filipek, Bartlomiej (16 de agosto de 2021). "Orden de evaluación de expresiones más estricto en C++ 17". Historias de C++ . Consultado el 24 de agosto de 2021 .
  22. ^ ab Abelson, Harold ; Sussman, Gerald Jay (1996). "Orden normal y orden aplicativo". Estructura e interpretación de programas informáticos (2ª ed.). Cambridge, Massachusetts: MIT Press . ISBN 0-262-01153-0.Véase también la nota a pie de página Temp 576.
  23. ^ Reese, Richard M. (14 de octubre de 2015). Aprendizaje de la programación funcional Java. Packt Publishing Ltd. pág. 106.ISBN 978-1-78528-935-4.
  24. ^ Antani, Ved; Timms, Simón; Mantyla, Dan (31 de agosto de 2016). JavaScript: programación funcional para desarrolladores de JavaScript. Packt Publishing Ltd. pág. 614.ISBN 978-1-78712-557-5.
  25. ^ Seacord, Robert C. "EXP30-C. No dependa del orden de evaluación de los efectos secundarios". Estándar de codificación SEI CERT C. Universidad de Carnegie mellon . Consultado el 23 de agosto de 2021 .
  26. ^ Anglade, S.; Lacrampe, JJ; Queinnec, C. (octubre de 1994). «Semántica de combinaciones en esquema» (PDF) . Punteros Lisp de ACM SIGPLAN . VII (4): 15-20. doi :10.1145/382109.382669. S2CID  2987427.
  27. ^ "¿Por qué los argumentos de la función OCaml se evalúan de derecha a izquierda?". OCaml . 30 de noviembre de 2017.
  28. ^ abcde Tremblay, G. (abril de 2000). "La evaluación indulgente no es ni estricta ni perezosa". Lenguajes informáticos . 26 (1): 43–66. CiteSeerX 10.1.1.137.9885 . doi :10.1016/S0096-0551(01)00006-6. 
  29. ^ George, Lai (marzo de 1987). Evaluación eficiente del orden normal a través de información de rigor (MSc). Universidad de Utah. pag. 10.
  30. ^ Borning, Alan (otoño de 1999). "Evaluación de orden aplicativo versus normal en lenguajes funcionales" (PDF) . CSE 505: Conceptos de lenguajes de programación . Universidad de Washington . Consultado el 23 de agosto de 2021 .
  31. ^ Mazzola, Guerino; Milmeister, Gerard; Weissmann, Jody (21 de octubre de 2004). Matemáticas integrales para informáticos 2. Springer Science & Business Media. pag. 323.ISBN 978-3-540-20861-7.
  32. ^ ab Sturm, Oliver (11 de abril de 2011). Programación funcional en C#: técnicas de programación clásicas para proyectos modernos. John Wiley e hijos. pag. 91.ISBN 978-0-470-74458-1.
  33. ^ Marlow, Simón. "¿Por qué no puedo obtener un seguimiento de la pila?". Taller de implementadores de Haskell 2012 . Consultado el 25 de agosto de 2021 .
  34. ^ Nilsson, Henrik (1999). "Seguimiento pieza por pieza: depuración asequible para lenguajes funcionales perezosos". Actas de la cuarta conferencia internacional ACM SIGPLAN sobre programación funcional . págs. 36–47. CiteSeerX 10.1.1.451.6513 . doi :10.1145/317636.317782. ISBN  1581131119. S2CID  13954359.
  35. ^ "Abrir parámetros de matriz". www.freepascal.org . Consultado el 20 de enero de 2024 .
  36. ^ abcd "¡Java se pasa por valor, maldita sea!". 16 de mayo de 2001 . Consultado el 24 de diciembre de 2016 .
  37. ^ Coenen, Frans. "PASO DE PARÁMETROS". cgi.csc.liv.ac.uk.Consultado el 22 de enero de 2024 .
  38. ^ "Llamada por referencia, problemas de alias" (PDF) . Curso MPRI 2-36-1: Prueba de programa (notas de la conferencia) . pag. 53.
  39. ^ Manual de referencia del lenguaje Ada 2022 (PDF) , 13 de octubre de 2023, p. 215
  40. ^ Barnes, Juan (2013). Justificación de Ada 2012: el lenguaje, las bibliotecas estándar (PDF) . Heidelberg: Springer. pag. 15-16,87-88. ISBN 978-3-642-45210-9.
  41. ^ Thurlow, Robert (mayo de 2009). "RPC: Especificación del protocolo de llamada a procedimiento remoto versión 2". herramientas.ietf.org . IETF . Consultado el 7 de abril de 2018 .
  42. ^ Lundh, Fredrik. "Llamada por objeto". Effbot.org . Archivado desde el original el 19 de mayo de 2011 . Consultado el 19 de mayo de 2011 .
  43. ^ Jones, precio de Rhys (2010). "¿El esquema es de llamada por valor?". Laboratorio 9 de lenguajes de programación CS 145: paso de parámetros . Universidad George Washington. Archivado desde el original el 16 de octubre de 2014 . Consultado el 20 de enero de 2024 .
  44. ^ "Procedimientos de la biblioteca Tcl: página del manual Tcl_Obj". www.tcl.tk.
  45. ^ "CA1021: Evitar parámetros". Microsoft. 15 de noviembre de 2016.
  46. ^ Leo, Ray (noviembre de 1996). Pequeño C ++ (simplemente fácil). LeoSudo Inc. págs. 79–80. ISBN 978-0-9654634-1-6.
  47. ^ Dandamudi, Sivarama P. (15 de julio de 2005). Guía para la programación en lenguaje ensamblador en Linux. Medios de ciencia y negocios de Springer. pag. 232.ISBN 978-0-387-25897-3.
  48. ^ Srivastava, SK; Srivastava, Deepali (6 de junio de 2018). C en profundidad. Publicaciones BPB. pag. 206.ISBN 978-93-87284-94-4.
  49. ^ "Variables mutables y tipos de referencia". okmij.org . Consultado el 20 de enero de 2024 .
  50. ^ Vermeir, Dirk (28 de junio de 2011). Programación multiparadigma utilizando C++. Medios de ciencia y negocios de Springer. págs. 10-11. ISBN 978-1-4471-0311-0.
  51. ^ McCollin, Thomas Gwynfryn; Morell, Tobías. "Un juego de paradigmas: un estudio de usabilidad de modismos funcionales en la programación de juegos" (PDF) . Universidad de Aalborg. pag. 6 . Consultado el 11 de enero de 2022 .
  52. ^ ab Schauser, Klaus E.; Goldstein, Seth C. (1995). "¿Cuánta rigurosidad requieren los programas indulgentes?" (PDF) . Actas de la séptima conferencia internacional sobre lenguajes de programación funcional y arquitectura informática - FPCA '95 . págs. 216-225. doi :10.1145/224164.224208. ISBN 0897917197. S2CID  2045943 . Consultado el 7 de enero de 2022 .
  53. ^ Ennals, Robert; Jones, Simon Peyton (agosto de 2003). "Evaluación optimista: una estrategia de evaluación rápida para programas no estrictos".

Otras lecturas

enlaces externos