Warum wird println als unreine Funktion angesehen?


10

Ich lese die Buchprogrammierung in Scala und es heißt:

... in diesem Fall wird als Nebeneffekt auf den Standardausgabestream gedruckt.

und ich sehe nicht, wo der Nebeneffekt liegt, da println für dieselbe Eingabe dieselbe Ausgabe druckt (glaube ich), zum Beispiel jedes Mal, wenn wir Folgendes aufrufen:
UPDATE
:

println(5)

es wird 5 gedruckt , ich sehe keinen Fall, in dem ein Aufruf println(5)einen anderen Wert als 5 druckt !!


Wenn dies Ihre Frage beantwortet, lösche ich meine Antwort softwareengineering.stackexchange.com/q/40297/271736
joelb

3
Antworten unter Was ist referenzielle Transparenz? scheinen hier relevant.
Nathan Hughes


2
Sie haben die Nebenwirkung (nicht referenziell transparent) mit deterministisch verwechselt. printlnist eine deterministische Funktion, aber um rein zu sein, muss es auch RT sein.
Bob

2
Weil es etwas anderes tut, als ein Ergebnis zu berechnen und es zurückzugeben.
Seth Tisue

Antworten:


6

Sie können feststellen, ob ein Ausdruck eine Nebenwirkung hat, indem Sie den Ausdruck durch sein Ergebnis ersetzen. Wenn das Programm seine Bedeutung ändert , tritt ein Nebeneffekt auf. Zum Beispiel,

println(5)

ist ein anderes Programm als

()

Das heißt, ein Nebeneffekt ist ein beobachtbarer Effekt, der im Ergebnis der Auswertung eines Ausdrucks nicht codiert wird. Hier ist das Ergebnis (), aber nichts in diesem Wert kodiert die Tatsache, dass 5 jetzt irgendwo auf Ihrem Bildschirm angezeigt wurde.


6
Eigentlich ist das keine gute Definition eines "Nebeneffekts" - Ein Nebeneffekt kann als alles definiert werden, was die referenzielle Transparenz bricht. Was Sie hier zeigen wollten, war RT, aber Ihr Beispiel ist falsch. Da das mehrfache Ausführen von etwas mehrmals dasselbe tun sollte - val a = println("hello"); val b = (a, a)sollte eher dasselbe sein wie val b = (pritnln("hello"), println("hello")).
Luis Miguel Mejía Suárez

1
@ LuisMiguelMejíaSuárez Vielleicht ist mein Beispiel nicht klar, aber ich denke nicht, dass es falsch ist. Ich weise im Wesentlichen auf den Unterschied zwischen dem Programm println(5)und hin (). Oder meintest du den letzten Satz?
Joelb

Ja, aber du warst dir nicht klar darüber. Da das Problem, wie gesagt, nicht mehrmals aufgerufen wird, besteht das Problem darin, dass das Ersetzen einer Referenz durch ihre Definition diese Auswirkung haben würde.
Luis Miguel Mejía Suárez

Ich verstehe Ihr Beispiel nicht klar
aName

5
Ich würde sagen, es ist falsch, weil es durchaus möglich ist, dass etwas einen Nebeneffekt hat und idempotent ist. Wenn Sie es also wiederholen, ändert sich der Effekt nicht. ZB Zuordnung zu einer veränderlichen Variablen; Wie können Sie unterscheiden x = 1und x = 1; x = 1; x = 1?
Alexey Romanov

5

Betrachten Sie die folgende Analogie

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

Dies myprintlnist unrein, da neben der Rückgabe des Werts ()auch eine nicht lokale Variable outals Nebeneffekt mutiert wird . Stellen Sie outsich nun vor , der Strom Vanille printlnmutiert.


1
Vielen Dank für Ihre Antwort. Es ist klar, dass Ihre Funktion unrein ist. Warum println (), wie in scala definiert, jedoch nicht rein ist
aName

1
@aName Weil es neben der Rückgabe von Wert ()auch den nicht-lokalen Status in mutiert System.out.
Mario Galic

Ich denke, die entscheidende Tatsache, die in dieser Antwort fehlt, ist, dass println der Eingabe ein Zeilenumbruchzeichen hinzufügt.
Federico S

4

Die Nebenwirkung liegt im Zustand des Computers. Bei jedem Aufruf println()ändert sich der Speicherstatus, um dem Terminal den angegebenen Wert anzuzeigen. Oder allgemeiner wird der Status des Standardausgabestreams geändert.


1
Teilweise wahr, führen Sie eine Operation aus, die dem Zustand des Befehlszählers entspricht, daher ist alles eine Nebenwirkung. Die Definition von Nebenwirkungen leitet sich von der Definition der referenziellen Transparenz ab, die viele Menschen in Bezug auf Änderungen an einem gemeinsamen veränderlichen Zustand definieren.
Luis Miguel Mejía Suárez

2
Auf diese Weise wird jede Funktion, Operation .... unrein sein, da sie den Zustand der Speicher-CPU ändert .....,
aName

2

Auf diese Frage wurden bereits nette Antworten gegeben, aber lassen Sie mich meine zwei Cent hinzufügen.

Wenn Sie sich die printlnFunktion im Wesentlichen ansehen , ist dies dasselbe wie java.lang.System.out.println()- Wenn Sie also die Standardbibliotheksmethode von Scala printlnunter der Haube aufrufen, wird eine Methode printlnfür eine PrintStreamObjektinstanz aufgerufen, die als Feld outin der SystemKlasse (oder genauer outVarin ConsoleObjekt) deklariert ist , wodurch der interne Status geändert wird . Dies kann als eine weitere Erklärung angesehen werden, warum printlneine unreine Funktion vorliegt.

Hoffe das hilft!


1

Es hat mit dem Konzept der referenziellen Transparenz zu tun . Ein Ausdruck ist referenziell transparent, wenn Sie ihn durch das ausgewertete Ergebnis ersetzen können, ohne das Programm zu ändern .

Wenn ein Ausdruck nicht referenziell transparent ist, sagen wir, dass er Nebenwirkungen hat .

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

während

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)

Eine ausführlichere Erklärung finden Sie hier: https://typelevel.org/blog/2017/05/02/io-monad-for-cats.html


Ich verstehe nicht, warum f (x, x) sich von f (println ("Effekt"), println ("Effekt")) unterscheidet !!
aName

f(println("effect"), println("effect"))wird zweimal im Konsoleneffekt val x = println("effect");f(x,x)gedruckt, während einmal gedruckt wird.
Didac Montero

Was ist die Definition der Funktion f
aName
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.