Mengapa println dianggap sebagai fungsi yang tidak murni?

10

Saya membaca pemrograman buku dalam scala, dan dikatakan:

... dalam hal ini, efek sampingnya adalah mencetak ke aliran keluaran standar.

dan saya tidak melihat di mana efek sampingnya, karena, untuk input yang sama, println akan mencetak output yang sama (saya pikir)
PEMBARUAN
misalnya setiap kali kita memanggil:

println(5)

itu akan mencetak 5 , saya tidak melihat kasus di mana panggilan println(5)akan mencetak nilai selain 5 !!

sebuah nama
sumber
jika ini menjawab pertanyaan Anda, saya akan menghapus jawaban saya softwareengineering.stackexchange.com/q/40297/271736
joelb
3
Jawaban di Apa itu transparansi referensial? tampaknya relevan di sini.
Nathan Hughes
1
terkait (lol) stackoverflow.com/q/4865616/5986907
joelb
2
Anda bingung efek samping (tidak transparan referensial) dengan deterministik. printlnadalah fungsi deterministik tetapi untuk menjadi murni juga harus RT.
bob
2
Karena ia melakukan sesuatu selain menghitung hasil dan mengembalikannya.
Seth Tisue

Jawaban:

6

Anda dapat mengetahui apakah suatu ekspresi memiliki efek samping dengan mengganti ekspresi dengan hasilnya. Jika program berubah arti , ada efek samping. Sebagai contoh,

println(5)

adalah program yang berbeda dengan

()

Artinya, efek samping adalah setiap efek yang dapat diamati yang tidak dikodekan dalam hasil mengevaluasi suatu ekspresi. Di sini hasilnya (), tetapi tidak ada dalam nilai yang mengkodekan fakta bahwa 5 sekarang telah muncul di suatu tempat di layar Anda.

joelb
sumber
6
Sebenarnya itu bukan definisi yang baik dari "efek samping" - Efek samping dapat didefinisikan sebagai apa pun yang merusak transparansi referensial. Apa yang Anda coba perlihatkan di sini adalah RT tetapi contoh Anda salah. Sejak mengeksekusi sesuatu berkali-kali harus melakukan hal yang sama mutiple kali - Sebaliknya, val a = println("hello"); val b = (a, a)harus sama dengan val b = (pritnln("hello"), println("hello")).
Luis Miguel Mejía Suárez
1
@ LuisMiguelMejíaSuárez mungkin contoh saya tidak jelas, tapi saya tidak berpikir itu salah. Saya pada dasarnya menunjukkan perbedaan antara program println(5)dan (). Atau maksud Anda kalimat terakhir?
joelb
Ya tapi kamu tidak jelas tentang itu. Karena, seperti yang saya katakan, masalahnya bukan memanggil sesuatu berkali-kali, masalahnya adalah jika mengganti referensi dengan definisinya akan berdampak seperti itu.
Luis Miguel Mejía Suárez
Saya tidak mengerti dengan jelas contoh Anda
aName
5
Saya akan mengatakan itu salah karena sangat mungkin sesuatu memiliki efek samping dan menjadi idempoten sehingga mengulanginya tidak mengubah efeknya. Misalnya penugasan ke variabel yang bisa berubah; bagaimana Anda bisa membedakan x = 1dan x = 1; x = 1; x = 1?
Alexey Romanov
5

Perhatikan analogi berikut ini

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

Ini myprintlntidak murni karena selain mengembalikan nilai (), variabel ini juga bermutasi outsebagai variabel non-lokal sebagai efek samping. Sekarang bayangkan outvanilla printlnbermutasi.

Mario Galic
sumber
1
terima kasih, untuk merespons, jelas bahwa fungsi Anda tidak murni, namun, mengapa println (), sebagaimana didefinisikan dalam scala, tidak murni
aName
1
@ aName Karena selain mengembalikan nilai, ()ia juga mengubah status non-lokal di System.out.
Mario Galic
Saya pikir fakta penting yang hilang dari jawaban ini adalah println menambahkan karakter baris baru ke input.
Federico S
4

Efek sampingnya ada pada kondisi komputer. Setiap kali Anda memanggil println()status memori berubah untuk menampilkan nilai yang diberikan ke terminal. Atau lebih umum, keadaan aliran output standar diubah.

Magang Kode
sumber
1
Sebagian benar, menjalankan operasi apa pun akan keadaan konter instruksi, sehingga segala sesuatu adalah efek samping. Definisi efek samping berasal dari definisi transparansi referensial, yang banyak orang definisikan dalam hal modifikasi menjadi keadaan yang bisa diubah bersama.
Luis Miguel Mejía Suárez
2
dengan cara ini, setiap fungsi, operasi .... akan tidak murni, karena itu berubah, status memori cpu .....,
aName
2

Jawaban yang bagus sudah diberikan untuk pertanyaan ini, tetapi izinkan saya menambahkan dua sen saya.

Jika Anda akan melihat ke dalam printlnfungsi dasarnya itu sama dengan java.lang.System.out.println()- jadi ketika Anda memanggil printlnmetode perpustakaan standar Scala di bawah tenda itu memanggil metode printlnpada PrintStreamcontoh objek yang dinyatakan sebagai bidang outdi Systemkelas (atau lebih tepatnya outVardi Consoleobjek), yang mengubahnya keadaan internal . Ini dapat dianggap sebagai penjelasan satu lagi mengapa printlnfungsi tidak murni.

Semoga ini membantu!

Ivan Kurchenko
sumber
1

Ini ada hubungannya dengan konsep transparansi referensial . Ekspresi transparan referensial jika Anda bisa menggantinya dengan hasil yang dievaluasi tanpa mengubah program .

Ketika sebuah ekspresi tidak transparan secara referensial kita mengatakan bahwa itu memiliki efek samping .

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

sementara

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)

Anda dapat menemukan penjelasan lebih rinci di sini: https://typelevel.org/blog/2017/05/02/io-monad-for-cats.html

Didac Montero
sumber
Saya tidak melihat mengapa f (x, x) berbeda dari f (println ("effect"), println ("effect")) !!
aName
f(println("effect"), println("effect"))akan mencetak dua kali di konsol "efek" saat val x = println("effect");f(x,x)akan mencetak sekali.
Didac Montero
apa definisi dari fungsi f
aName