¿Por qué println se considera una función impura?

10

Estoy leyendo la programación del libro en scala, y se dice:

... en este caso, su efecto secundario es imprimir en la secuencia de salida estándar.

y no veo dónde está el efecto secundario, ya que, para la misma entrada, println imprimirá la misma salida (creo)
ACTUALIZAR,
por ejemplo, cada vez que llamemos:

println(5)

imprimirá 5 , ¡no veo un caso en el que llamar println(5)imprima un valor diferente a 5!

un nombre
fuente
si esto responde a su pregunta, eliminaré mi respuesta softwareengineering.stackexchange.com/q/40297/271736
joelb
3
Respuestas en ¿Qué es la transparencia referencial? Parece relevante aquí.
Nathan Hughes
1
relacionado (lol) stackoverflow.com/q/4865616/5986907
joelb
2
Confundió el efecto secundario (no referencial transparente) con determinista. printlnes una función determinista pero para ser pura también debe ser RT.
bob
2
Porque hace algo más que calcular un resultado y devolverlo.
Seth Tisue

Respuestas:

6

Puede saber si una expresión tiene un efecto secundario reemplazando la expresión con su resultado. Si el programa cambia de significado , hay un efecto secundario. Por ejemplo,

println(5)

es un programa diferente para

()

Es decir, un efecto secundario es cualquier efecto observable que no está codificado en el resultado de evaluar una expresión. Aquí el resultado es (), pero no hay nada en ese valor que codifique el hecho de que ahora 5 ha aparecido en algún lugar de su pantalla.

joelb
fuente
66
En realidad, esa no es una buena definición de un "efecto secundario" : un efecto secundario puede definirse como cualquier cosa que rompa la transparencia referencial. Lo que trataste de mostrar aquí fue RT, pero tu ejemplo es incorrecto. Dado que ejecutar algo varias veces debería hacer lo mismo varias veces, más bien val a = println("hello"); val b = (a, a)debería ser lo mismo que val b = (pritnln("hello"), println("hello")).
Luis Miguel Mejía Suárez
1
@ LuisMiguelMejíaSuárez quizás mi ejemplo no está claro, pero no creo que esté mal. Básicamente estoy señalando la diferencia entre el programa println(5)y (). ¿O quisiste decir la última oración?
Joelb
Sí, pero no estabas claro al respecto. Como, como dije, el problema no es llamar a algo varias veces, el problema es si reemplazar una referencia con su definición tendría ese impacto.
Luis Miguel Mejía Suárez
No entiendo claramente tu ejemplo
nombre
55
Diría que está mal porque es perfectamente posible que algo tenga un efecto secundario y sea idempotente, por lo que repetirlo no cambia el efecto. Por ejemplo, asignación a una variable mutable; ¿Cómo puedes distinguir x = 1y x = 1; x = 1; x = 1?
Alexey Romanov
5

Considere la siguiente analogía

var out: String = ""
def myprintln(s: String) = {
  out += s // this non-local mutation makes me impure
  ()
}

Aquí myprintlnes impuro porque, además del valor de retorno (), también muta la variable no local outcomo efecto secundario. Ahora imagina outque la corriente vainilla printlnmuta.

Mario Galic
fuente
1
gracias, por responder, está claro que su función es impura, sin embargo, por qué println (), como se define en scala, no es puro
aName
1
@aName Porque además de devolver el valor (), también muta el estado no local en System.out.
Mario Galic
Creo que el hecho crucial que falta en esta respuesta es que println agrega un carácter de nueva línea a la entrada.
Federico S
4

El efecto secundario está en el estado de la computadora. Cada vez que llama println()el estado de los cambios de memoria para mostrar el valor dado al terminal. O, más generalmente, se cambia el estado del flujo de salida estándar.

Aprendiz de código
fuente
1
Parcialmente cierto, ejecutar cualquier operación sería el estado del contador de instrucciones, por lo tanto, cualquier cosa es un efecto secundario. La definición de efectos secundarios deriva de la definición de transparencia referencial, que muchas personas definen en términos de modificaciones a un estado mutable compartido.
Luis Miguel Mejía Suárez
2
de esta manera, cualquier función, operación ... será impura, ya que cambia, el estado de la memoria de la CPU .....,
unNombre
2

Ya se dieron buenas respuestas a esta pregunta, pero permítanme agregar mis dos centavos.

Si observará la printlnfunción interna esencialmente, es lo mismo que java.lang.System.out.println(), por lo tanto, cuando invoca el printlnmétodo de biblioteca estándar de Scala debajo del capó, invoca el método printlnen la PrintStreaminstancia del objeto que se declara como campo outen la Systemclase (o más precisamente outVaren el Consoleobjeto), que cambia su estado interno . Esto puede considerarse como otra explicación de por qué printlnes una función impura.

¡Espero que esto ayude!

Ivan Kurchenko
fuente
1

Tiene que ver con el concepto de transparencia referencial . Una expresión es referencialmente transparente si puede sustituirla con su resultado evaluado sin cambiar el programa .

Cuando una expresión no es referencialmente transparente, decimos que tiene efectos secundarios .

f(println("effect"), println("effect"))
// isn't really equivalent to!
val x = println("effect")
f(x, x)

mientras

import cats.effect.IO

def printlnIO(line: String): IO[Unit] = IO(println(line))

f(printlnIO("effect"), printlnIO("effect"))
// is equivalent to
val x = printlnIO("effect")
f(x, x)

Puede encontrar una explicación más detallada aquí: https://typelevel.org/blog/2017/05/02/io-monad-for-cats.html

Didac Montero
fuente
No veo por qué f (x, x) es diferente de f (println ("efecto"), println ("efecto")) !!
aName
f(println("effect"), println("effect"))va a imprimir dos veces en "efecto" de consola mientras val x = println("effect");f(x,x)que va a imprimir una vez.
Didac Montero
¿
Cuál