Println neden saf olmayan bir işlev olarak kabul edilir?


10

Scala'da kitap programlamayı okuyorum ve söylendi:

... bu durumda yan etkisi standart çıktı akışına yazdırılıyor.

ve aynı etki için println aynı çıktıyı (sanırım)
UPDATE'i
her zaman aradığımızda yazdırdığından, yan etkinin nerede olduğunu görmüyorum :

println(5)

5 yazdıracak , aramanın println(5)5 dışında bir değer yazacağı bir durum görmüyorum !!


bu soruya cevap verirse, cevabımı silerim softwareengineering.stackexchange.com/q/40297/271736
joelb

3
En Cevapları referans şeffaflık Ne nedir? burada alakalı görünüyor.
Nathan Hughes


2
Yan etkiyi (referans şeffaf değil) deterministikle karıştırdınız. printlndeterministik bir fonksiyondur, ancak saf olabilmek için RT de olmalıdır.
bob

2
Çünkü bir sonucu hesaplayıp geri döndürmekten başka bir şey yapar.
Seth Tisue

Yanıtlar:


6

İfadeyi sonucuyla değiştirerek bir ifadenin yan etkisi olup olmadığını anlayabilirsiniz. Program anlamını değiştirirse , bir yan etkisi vardır. Örneğin,

println(5)

farklı bir programdır

()

Yani, bir yan etki, bir ifadenin değerlendirilmesi sonucunda kodlanmamış herhangi bir gözlemlenebilir etkidir. İşte sonuç (), ancak bu değerde 5'in artık ekranınızda bir yerde göründüğünü kodlayan hiçbir şey yok.


6
Aslında bu bir "yan etki" nin iyi bir tanımı değildir - Yan etki, referans şeffaflığını bozan herhangi bir şey olarak tanımlanabilir. Burada göstermeye çalıştığınız şey RT idi, ancak örneğiniz yanlış. Bir şeyi birden çok kez yürütmek, aynı şeyi aynı anda val a = println("hello"); val b = (a, a)yapmalıdır - Aksine, aynı olmalıdır val b = (pritnln("hello"), println("hello")).
Luis Miguel Mejía Suárez

1
@ LuisMiguelMejíaSuárez belki de örneğim net değil, ama bunun yanlış olduğunu düşünmüyorum. Aslında program println(5)ile arasındaki farkı işaret ediyorum (). Yoksa son cümleyi mi demek istediniz?
joelb

Evet ama bu konuda net değildin. Söylediğim gibi, sorun birden fazla kez bir şey çağırmıyor, çünkü bir referansın tanımıyla değiştirilmesinin bu etkisi olacaktır.
Luis Miguel Mejía Suárez


5
Bunun yanlış olduğunu söyleyebilirim, çünkü bir şeyin yan etkisi olması ve idempotent olması mükemmeldir, bu yüzden tekrarlamak etkiyi değiştirmez. Değişebilir bir değişkene atama; nasıl ayırt edebilirsin x = 1ve x = 1; x = 1; x = 1?
Alexey Romanov

5

Aşağıdaki benzetmeyi düşünün

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

Burada myprintlnsaf olmayan bir değerdir çünkü geri dönen değerin yanı sıra ()yerel olmayan değişkeni outbir yan etki olarak mutasyona uğratır . Şimdi outakış vanilya printlnmutasyonları olduğunu hayal edin .


1
teşekkür ederiz, yanıt verdiğiniz için, işlevinizin saf olmadığı açıktır, ancak scala'da tanımlandığı gibi println () neden saf değildir
aName

1
@aName Değer döndürmenin yanı sıra ()yerel olmayan durumu da değiştirir System.out.
Mario Galic

Bu cevap eksik olan önemli gerçeği düşünüyorum println giriş newline karakter ekler.
Federico S

4

Yan etki bilgisayarın durumundadır. println()Bellek durumunu her aradığınızda , terminale verilen değeri görüntülemek için değişir. Veya daha genel olarak, standart çıkış akımının durumu değiştirilir.


1
Kısmen doğru, herhangi bir işlemi yürütmek talimat sayacının durumunu olurdu, bu nedenle her şey bir yan etkidir. Yan etkinin tanımı, birçok insanın paylaşılan bir değişebilir durumdaki değişiklikler açısından tanımladığı referans şeffaflığının tanımından kaynaklanmaktadır.
Luis Miguel Mejía Suárez

2
Bu şekilde, herhangi bir işlev, işlem .... değişmeyecek, bellek cpu durumu .....,
aName

2

Bu soruya çoktan güzel cevaplar verilmişti, ama iki kuruşumu ekleyeyim.

İçeri bakacağız Eğer printlnfonksiyonu aslında bu aynıdır java.lang.System.out.println()- yani sizi Scala'nın standart kütüphane çağırmak printlno yöntemini çağırır başlık altında yöntemine printlnüzerinde PrintStreamalan olarak ilan edilir nesne örneği outiçinde System(daha doğrusu veya sınıf outVariçinde Consoleiç durumunu değiştirir nesne), . Bu neden printlnsaf olmayan fonksiyonun başka bir açıklaması olarak düşünülebilir .

Bu yardımcı olur umarım!


1

Referans şeffaflığı kavramıyla ilgilidir . Bir ifadeyi, programı değiştirmeden değerlendirilen sonucuyla değiştirebiliyorsanız referans olarak saydamdır .

Bir ifade referans olarak şeffaf olmadığında, bunun yan etkileri olduğunu söyleriz .

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

süre

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)

Daha ayrıntılı bir açıklama burada bulabilirsiniz: https://typelevel.org/blog/2017/05/02/io-monad-for-cats.html


Neden f (x, x) 'nin f (println ("effect"), println ("effect"))' den farklı olduğunu anlamıyorum!
aName

f(println("effect"), println("effect"))konsoldan "efekt" iki kez basarken val x = println("effect");f(x,x), bir kez basar.
Didac Montero

f
aName
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.