2012-05-22 12 views
27

Según la entrada de la wikipedia para side effect, presentar una excepción constituye un efecto secundario. Considere esta función pitón simple:¿Por qué el aumento de una excepción es un efecto secundario?

def foo(arg): 
    if not arg: 
     raise ValueError('arg cannot be None') 
    else: 
     return 10 

Invocando con foo(None) habrá siempre se pueden cumplir con una excepción. La misma entrada, la misma salida. Es referencialmente transparente. ¿Por qué esto no es una función pura?

+0

La excepción no se devuelve simplemente como un valor de retorno. – Sjoerd

+4

Mover para reabrir esto es claramente una pregunta, mientras que la naturaleza más teórica aún es válida para este sitio web. – Woot4Moo

+0

Se debe migrar a [programadores.se] – Daenyth

Respuesta

10

Desde la primera línea:

"En informática, se dice que una función o expresión que tiene un efecto secundario si, además de devolver un valor, sino que también modifica algún estado o tiene una interacción observable con funciones de llamada o el mundo exterior "

El estado que modifica es la finalización del programa. Para responder a su otra pregunta sobre por qué no es una función pura. La función no es pura porque lanzar una excepción termina el programa, por lo tanto, tiene un efecto secundario (el programa finaliza).

+0

La terminación no es un efecto. No es un estado que se puede compartir. Muchas funciones parciales puras no terminan, o están definidas solo parcialmente. Ellos todavía son puros. La división por cero es una función pura, por ejemplo, que falla. –

+5

Don: En realidad, la no terminación (también conocida como parcialidad) a menudo * se * considera un efecto, especialmente cuando las personas están interesadas en cosechar el isomorfismo de Curry/Howard y usan tipos como proposiciones. –

+0

Ok. Lo compraré si distinguimos funciones totales y parciales. –

4

La transparencia referencial también es la posibilidad de reemplazar un cálculo (por ejemplo, una invocación de función) con el resultado del cálculo en sí, algo que no puede hacer si su función genera una excepción. ¡Esto se debe a que las excepciones no forman parte de la computación, pero deben ser atrapadas!

+1

Bueno, eso puede ser cierto si no hay excepciones. Pero si los hay, puede lanzar una excepción en lugar de ejecutar la función (analógico para devolver un valor en lugar de ejecutar la función). – valenterry

24

La pureza solo se infringe si observa la excepción y toma una decisión basada en ella que cambia el flujo de control. En realidad, arrojar un valor de excepción es referencialmente transparente: es semánticamente equivalente a la no terminación u otra llamada bottom values.

Si una función (pura) no es total, se evalúa como un valor inferior. Cómo se codifica el valor inferior depende de la implementación; podría ser una excepción; o no terminación, o dividiendo por cero, o alguna otra falla.

Considérese la función pura:

f :: Int -> Int 
f 0 = 1 
f 1 = 2 

Esto no se define para todas las entradas. Para algunos, se evalúa abajo. La implementación codifica esto lanzando una excepción. Debe ser semánticamente equivalente al uso de un tipo Maybe o Option.

Ahora, sólo se rompen transparencia referencial cuando se observa el valor inferior, y tomar decisiones basadas en ella - lo que podría introducir no determinismo tantas excepciones diferentes pueden ser lanzadas, y no se puede saber cuál . Por esta razón, la captura de excepciones se encuentra en la mónada IO en Haskell, mientras que la generación de los llamados "imprecise" exceptions se puede hacer de manera pura.

Por lo tanto, no es cierto que presentar una excepción sea un efecto secundario como tal. Es la cuestión de si se puede o no modificar el comportamiento de una función pura basada en un valor excepcional, rompiendo así la transparencia referencial.

+2

Interesante, siempre pensé que la definición de RT era si pudieras reemplazar una expresión por su valor, y no puedes tener el valor de "lanza la excepción A". –

+0

@ JedWesley-Smith Tiene razón. Cuando una función genera una excepción, no puede devolver un valor y ha roto la transparencia referencial. La notación incorrecta de que RT solo se rompe cuando se maneja la excepción es conveniente, ya que permite empujar los detalles desordenados del modelado completo del dominio a las personas que llaman de las funciones que generan excepciones. –

4

La generación de una excepción puede ser pura O no pura, solo depende del tipo de excepción que se produzca. Una buena regla empírica es si la excepción es planteada por código, es pura, pero si el hardware la plantea, generalmente debe clasificarse como no pura.

Esto se puede ver mirando lo que ocurre cuando el hardware hace una excepción: Primero se genera una señal de interrupción, luego el manejador de interrupciones comienza a ejecutarse. El problema aquí es que el manejador de interrupciones no era un argumento para su función ni especificado en su función, sino una variable global. Cada vez que se lee o escribe una variable global (también conocida como estado), ya no tiene una función pura.

Compárelo con una excepción que aparece en su código: construye el valor de excepción a partir de un conjunto de argumentos o constantes de ámbito local conocido y "arroja" el resultado. No hay variables globales utilizadas. El proceso de arrojar una excepción es esencialmente azúcar sintáctica proporcionada por su idioma, no introduce ningún comportamiento no determinista o no puro. Como dijo Don, "debe ser semánticamente equivalente a usar un tipo Maybe o Option", lo que significa que también debe tener todas las mismas propiedades, incluida la pureza.

Cuando dije que levantar una excepción de hardware "generalmente" se clasifica como un efecto secundario, no siempre tiene que ser el caso. Por ejemplo, si la computadora en la que se ejecuta su código no llama a una interrupción cuando genera una excepción, sino que empuja un valor especial a la pila, entonces no es clasificable como no pura. Creo que el error NAN flotante IEEE se genera utilizando un valor especial y no una interrupción, por lo que cualquier excepción planteada al hacer matemáticas de coma flotante se puede clasificar como libre de efectos secundarios ya que el valor no se lee desde ningún estado global, pero sí una constante codificada en la FPU.

Considerando todos los requisitos para que un código pieza sea puro, las excepciones basadas en código y el azúcar sintáctico sintonizan todas las casillas, no modifican ningún estado, no tienen ninguna interacción con sus funciones de llamada ni nada externo su invocación, y son referencialmente transparentes, pero solo una vez que el compilador ha seguido su propio código.

Como todas las discusiones puras vs no puras, he excluido cualquier noción de tiempos de ejecución u operaciones de memoria y he operado bajo el supuesto de que cualquier función que PUEDA implementarse puramente se implementa puramente independientemente de su implementación real. Tampoco tengo evidencia del reclamo de excepción IANE punto flotante NAN.

Cuestiones relacionadas