Perché println è considerata una funzione impura?


10

Sto leggendo il libro programmando in scala, e si dice:

... in questo caso, il suo effetto collaterale è la stampa sul flusso di output standard.

e non vedo dove sia l'effetto collaterale, poiché, per lo stesso input, println stamperà lo stesso output (penso)
AGGIORNAMENTO
ad esempio ogni volta che chiamiamo:

println(5)

stampa 5 , non vedo un caso in cui la chiamata println(5)stamperà un valore diverso da 5 !!


se questo risponde alla tua domanda, eliminerò la mia risposta softwareengineering.stackexchange.com/q/40297/271736
joelb



2
Hai confuso l'effetto collaterale (non referenziale trasparente) con deterministico. printlnè una funzione deterministica ma per essere pura deve anche essere RT.
bob

2
Perché fa qualcosa di diverso dal calcolare un risultato e restituirlo.
Seth Tisue,

Risposte:


6

Puoi capire se un'espressione ha un effetto collaterale sostituendo l'espressione con il suo risultato. Se il programma cambia significato , c'è un effetto collaterale. Per esempio,

println(5)

è un programma diverso da

()

Cioè, un effetto collaterale è qualsiasi effetto osservabile che non è codificato nel risultato della valutazione di un'espressione. Qui il risultato è (), ma non c'è nulla in quel valore che codifica il fatto che 5 è ora apparso da qualche parte sullo schermo.


6
In realtà questa non è una buona definizione di "effetto collaterale" . Un effetto collaterale può essere definito come qualcosa che rompe la trasparenza referenziale. Quello che hai provato a mostrare qui era RT ma il tuo esempio è sbagliato. Dal momento che eseguire più volte qualcosa dovrebbe fare la stessa cosa volte multiple - Piuttosto, val a = println("hello"); val b = (a, a)dovrebbe essere lo stesso di val b = (pritnln("hello"), println("hello")).
Luis Miguel Mejía Suárez,

1
@ LuisMiguelMejíaSuárez forse il mio esempio non è chiaro, ma non penso che sia sbagliato. Sto essenzialmente sottolineando la differenza tra il programma println(5)e (). O intendevi l'ultima frase?
Joelb

Sì, ma non eri chiaro. Poiché, come ho già detto, il problema non sta chiamando qualcosa più volte, il problema è se la sostituzione di un riferimento con la sua definizione avrebbe quell'impatto.
Luis Miguel Mejía Suárez, il

Non capisco chiaramente il vostro esempio
aName

5
Direi che è sbagliato perché è perfettamente possibile che qualcosa abbia un effetto collaterale ed essere idempotente, quindi ripetere non cambia l'effetto. Ad esempio assegnazione a una variabile mutabile; come puoi distinguere x = 1e x = 1; x = 1; x = 1?
Alexey Romanov,

5

Considera la seguente analogia

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

Qui myprintlnè impuro perché, oltre a restituire valore (), muta anche outuna variabile non locale come effetto collaterale. Ora immagina outdi essere il flusso che printlnmuta la vaniglia .


1
grazie, per aver risposto, è chiaro che la tua funzione è impura, tuttavia, perché println (), come definito in scala, non è puro
aName

1
@aName Perché oltre a restituire valore (), muta anche lo stato non locale in System.out.
Mario Galic,

Penso che il fatto cruciale che manca a questa risposta sia che println aggiunge un carattere newline all'input.
Federico S,

4

L'effetto collaterale è nello stato del computer. Ogni volta che si chiama println()lo stato della memoria cambia per visualizzare un determinato valore sul terminale. O più in generale, lo stato del flusso di output standard viene modificato.


1
Parzialmente vero, eseguire qualsiasi operazione sarebbe lo stato del contatore di istruzioni, quindi tutto è un effetto collaterale. La definizione di effetto collaterale deriva dalla definizione di trasparenza referenziale, che molte persone definiscono in termini di modifiche a uno stato mutabile condiviso.
Luis Miguel Mejía Suárez,

2
in questo modo, qualsiasi funzione, operazione .... sarà impura, poiché cambia, lo stato della memoria cpu .....,
aName

2

Sono state già fornite delle belle risposte a questa domanda, ma vorrei aggiungere i miei due centesimi.

Se si guarda dentro printlnfunzione essenzialmente è lo stesso che java.lang.System.out.println()- in modo da quando invoke libreria standard di Scala printlnmetodo sotto il cofano che richiama il metodo printlnsu PrintStreamun'istanza di oggetto che viene dichiarato come campo outdi Systemclasse (o più precisamente outVarin Consoleoggetto), che cambia stato interno . Questo può essere considerato come un'altra spiegazione del perché la printlnfunzione impura.

Spero che sia di aiuto!


1

Ha a che fare con il concetto di trasparenza referenziale . Un'espressione è referenzialmente trasparente se è possibile sostituirla con il risultato valutato senza modificare il programma .

Quando un'espressione non è referenzialmente trasparente diciamo che ha effetti collaterali .

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

mentre

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)

Puoi trovare una spiegazione più dettagliata qui: https://typelevel.org/blog/2017/05/02/io-monad-for-cats.html


Non vedo perché f (x, x) sia diverso da f (println ("effect"), println ("effect")) !!
aName

f(println("effect"), println("effect"))sta per stampare due volte in "effetto" console mentre val x = println("effect");f(x,x)sta per stampare una volta.
Didac Montero,

qual è la definizione della funzione f
aName
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.