Por que println é considerado uma função impura?

10

Estou lendo o livro de programação em scala, e diz-se:

... neste caso, seu efeito colateral é imprimir no fluxo de saída padrão.

e não vejo onde está o efeito colateral, pois, para a mesma entrada, println imprimirá a mesma saída (acho)
UPDATE,
por exemplo, sempre que chamarmos:

println(5)

ele imprimirá 5 , não vejo um caso em que a chamada println(5)imprima um valor diferente de 5 !!

um nome
fonte
se isso responder sua pergunta, eu
excluirei
3
Respostas em O que é transparência referencial? parece relevante aqui.
Nathan Hughes
2
Você confundiu efeito colateral (não referencial transparente) com determinístico. printlné uma função determinística, mas, para ser pura, também deve ser RT.
bob
2
Porque ele faz algo diferente de calcular um resultado e devolvê-lo.
Seth Tisue

Respostas:

6

Você pode dizer se uma expressão tem um efeito colateral substituindo a expressão pelo seu resultado. Se o programa mudar de significado , há um efeito colateral. Por exemplo,

println(5)

é um programa diferente para

()

Ou seja, um efeito colateral é qualquer efeito observável que não é codificado no resultado da avaliação de uma expressão. Aqui está o resultado (), mas não há nada nesse valor que codifique o fato de que 5 agora apareceu em algum lugar da tela.

joelb
fonte
6
Na verdade, essa não é uma boa definição de "efeito colateral" - Um efeito colateral pode ser definido como qualquer coisa que quebre a transparência referencial. O que você tentou mostrar aqui foi RT, mas seu exemplo está errado. Como executar algo várias vezes deve fazer a mesma coisa várias vezes - Em vez disso, val a = println("hello"); val b = (a, a)deve ser o mesmo que val b = (pritnln("hello"), println("hello")).
Luis Miguel Mejía Suárez
11
@ LuisMiguelMejíaSuárez talvez meu exemplo não esteja claro, mas não acho que esteja errado. Estou essencialmente apontando a diferença entre o programa println(5)e (). Ou você quis dizer a última frase?
joelb 25/02
Sim, mas você não foi claro sobre isso. Como, como eu disse, o problema não está chamando algo várias vezes, o problema é se a substituição de uma referência por sua definição teria esse impacto.
Luis Miguel Mejía Suárez
Eu não entendo claramente o seu exemplo
aName
5
Eu diria que está errado, porque é perfeitamente possível que algo tenha um efeito colateral e seja idempotente, de modo que repeti-lo não muda o efeito. Por exemplo, atribuição a uma variável mutável; como você pode distinguir x = 1e x = 1; x = 1; x = 1?
Alexey Romanov
5

Considere a seguinte analogia

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

Aqui myprintlnestá impuro porque, além do valor retornado, ()ele também altera a variável não local outcomo efeito colateral. Agora imagine outser o fluxo que a baunilha printlnsofre mutação.

Mario Galic
fonte
11
obrigado, por responder, é claro que sua função é impura, no entanto, por que println (), conforme definido em scala, não é puro
aName
11
@aName Porque, além de retornar valor (), também altera o estado não local em System.out.
Mario Galic
Eu acho que o fato crucial que falta nesta resposta é que println adiciona um caractere de nova linha à entrada.
Federico S
4

O efeito colateral está no estado do computador. Cada vez que você chama, println()o estado da memória muda para exibir um determinado valor ao terminal. Ou, geralmente, o estado do fluxo de saída padrão é alterado.

Code-Apprentice
fonte
11
Parcialmente verdade, executar qualquer operação seria o estado do contador de instruções, portanto, qualquer coisa é um efeito colateral. A definição de efeito colateral deriva da definição de transparência referencial, que muitas pessoas definem em termos de modificações em um estado mutável compartilhado.
Luis Miguel Mejía Suárez
2
dessa forma, qualquer função, operação ... ficará impura, pois muda, estado da CPU da memória .....,
aName
2

Respostas legais já foram dadas a essa pergunta, mas deixe-me acrescentar meus dois centavos.

Se você olhar para dentro da printlnfunção, essencialmente é o mesmo que java.lang.System.out.println()- portanto, quando você chama o printlnmétodo de biblioteca padrão do Scala sob o capô, ele invoca o método printlnna PrintStreaminstância do objeto que é declarada como campo outna Systemclasse (ou mais precisamente outVarno Consoleobjeto), o que altera o estado interno . Isso pode ser considerado como outra explicação porque a printlnfunção é impura.

Espero que isto ajude!

Ivan Kurchenko
fonte
1

Tem a ver com o conceito de transparência referencial . Uma expressão é referencialmente transparente se você puder substituí-la pelo resultado avaliado sem alterar o programa .

Quando uma expressão não é referencialmente transparente, dizemos que ela tem efeitos colaterais .

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

enquanto

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)

Você pode encontrar uma explicação mais detalhada aqui: https://typelevel.org/blog/2017/05/02/io-monad-for-cats.html

Didac Montero
fonte
Não vejo por que f (x, x) é diferente de f (println ("efeito"), println ("efeito")) !!
aName
f(println("effect"), println("effect"))vai imprimir duas vezes no console "effect" enquanto val x = println("effect");f(x,x)vai imprimir uma vez.
Didac Montero
qual é a definição da função f
aName