Katakanlah kita memiliki fungsi murni normal seperti
function add(a, b) {
return a + b
}
Dan kemudian kita mengubahnya sedemikian rupa sehingga memiliki efek samping
function add(a, b) {
writeToDatabase(Math.random())
return a + b;
}
Itu tidak dianggap sebagai fungsi murni sejauh yang saya tahu karena saya sering mendengar orang menyebut fungsi murni "fungsi tanpa efek samping." Namun, ia berperilaku seperti fungsi murni sejauh fakta bahwa ia akan mengembalikan output yang sama untuk input yang sama.
Apakah ada nama yang berbeda untuk jenis fungsi ini, apakah itu tidak disebutkan namanya, atau apakah masih benar-benar murni dan saya salah tentang definisi kemurnian?
writeToDatabase
gagal itu dapat memicu pengecualian sehingga membuatadd
fungsi kedua Anda menghasilkan pengecualian kadang-kadang bahkan jika dipanggil dengan argumen yang sama yang sebelumnya tidak memiliki masalah ... sebagian besar waktu memiliki efek samping memperkenalkan jenis kondisi terkait kesalahan yang memecah "kemurnian input-output".F(x)
didefinisikan untuk kembalitrue
jika dipanggil dengan argumen yang sama dengan panggilan sebelumnya. Jelas dengan urutan{1,2,2} => {undefined, false, true}
ini adalah deterministik, namun memberikan hasil yang berbeda untukF(2)
.Jawaban:
Saya tidak yakin tentang definisi universal tentang kemurnian, tetapi dari sudut pandang Haskell (bahasa di mana programmer cenderung peduli tentang hal-hal seperti kemurnian dan transparansi referensial), hanya yang pertama dari fungsi Anda yang "murni". Versi kedua
add
tidak murni . Jadi sebagai jawaban atas pertanyaan Anda, saya akan menyebutnya "tidak murni";)Menurut definisi ini, fungsi murni adalah fungsi yang:
Dengan definisi ini, jelas fungsi kedua Anda tidak dapat dianggap murni, karena melanggar aturan 2. Artinya, dua program berikut ini TIDAK setara:
dan
Ini karena meskipun kedua fungsi akan mengembalikan nilai yang sama, fungsi
f
akan menulis ke database dua kali tetapig
akan menulis sekali! Sangat mungkin bahwa menulis ke basis data adalah bagian dari perilaku yang dapat diamati dari program Anda, dalam hal ini saya telah menunjukkan versi kedua Andaadd
tidak "murni".Jika menulis ke basis data bukan bagian yang dapat diamati dari perilaku program Anda, maka kedua versi
add
dapat dianggap setara dan murni. Tapi saya tidak bisa memikirkan skenario di mana menulis ke database tidak masalah. Bahkan masalah logging!sumber
f(x)
tidak hanya bergantung padax
, tetapi juga pada beberapa variabel global eksternaly
. Kemudian, jikaf
memiliki properti RT Anda dapat dengan bebas menukar semua kemunculannya dengan nilai pengembaliannya selama Anda tidak menyentuhy
. Ya, contoh saya meragukan. Tetapi yang penting adalah: jikaf
menulis ke database (atau menulis ke log) itu kehilangan properti RT: sekarang tidak masalah apakah Anda meninggalkan global yangy
tidak tersentuh, Anda tahu arti dari perubahan program Anda tergantung pada apakah Anda benar-benar hubungif
atau cukup gunakan nilai pengembaliannya.Fungsi seperti ini disebut
Tentang negara:
Bergantung pada definisi fungsi yang Anda gunakan, fungsi tidak memiliki status. Jika Anda berasal dari dunia berorientasi objek, ingatlah itu
x.f(y)
adalah metode. Sebagai fungsi akan terlihat sepertif(x,y)
. Dan jika Anda ingin menutup dengan lingkup leksikal tertutup ingat bahwa keadaan tidak berubah mungkin juga menjadi bagian dari ekspresi fungsi. Hanya keadaan yang bisa berubah yang akan memengaruhi fungsi yang sifatnya deterministik. Jadi f (x) = x + 1 adalah deterministik selama 1 tidak berubah. Tidak masalah di mana 1 disimpan.Fungsi Anda keduanya deterministik. Fungsi pertama Anda juga murni. Kedua Anda tidak murni.
Poin 1 berarti deterministik . Angka 2 berarti transparansi referensial . Bersama-sama mereka maksudkan fungsi murni hanya memungkinkan argumennya dan nilai yang dikembalikannya berubah. Tidak ada yang menyebabkan perubahan. Tidak ada yang berubah.
sumber
Math.random()
. Jadi tidak, kecuali kita mengasumsikan PRNG (bukan RNG fisik) DAN menganggap bahwa PRNG menyatakan bagian dari input (yang bukan, rujukannya adalah hardcoded), itu tidak deterministik.Jika Anda tidak peduli dengan efek sampingnya, maka itu transparan secara referensi. Tentu saja mungkin bahwa Anda tidak peduli tetapi orang lain tidak, sehingga penerapan istilah ini tergantung pada konteks.
Saya tidak tahu istilah umum untuk properti yang Anda jelaskan, tetapi bagian penting adalah yang idempoten . Dalam ilmu komputer, sedikit berbeda dengan matematika *, fungsi idempoten adalah fungsi yang dapat diulangi dengan efek yang sama; artinya efek samping nett dari melakukannya berkali-kali sama dengan melakukannya sekali.
Jadi, jika efek samping Anda adalah memperbarui database dengan nilai tertentu di baris tertentu, atau membuat file dengan konten yang persis konsisten, maka itu akan menjadi idempoten , tetapi jika itu ditambahkan ke database, atau ditambahkan ke file , maka tidak akan.
Kombinasi fungsi idempoten mungkin atau mungkin juga tidak idempoten secara keseluruhan.
* Penggunaan idempoten secara berbeda dalam ilmu komputer daripada matematika tampaknya berasal dari penggunaan istilah matematika yang salah yang kemudian diadopsi karena konsep ini berguna.
sumber
(f x, f x)
denganlet y = f x in (y, y)
akan berjalan keluar dari ruang disk-pengecualian dua kali lebih cepat Anda dapat berargumen bahwa ini adalah kasus tepi Anda tidak peduli, tetapi dengan definisi fuzzy seperti itu, kami mungkin juga menyebut secaranew Random().Next()
transparan transparan karena, saya tidak peduli berapa nomor yang saya dapatkan.Random.Next
di. NET memang memiliki efek samping. Sangat banyak sehingga. Jika Anda bisaNext
, tetapkan ke variabel lalu panggilNext
lagi dan tetapkan ke variabel lain, kemungkinan mereka tidak akan sama. Mengapa? Karena memohonNext
mengubah beberapa keadaan internal tersembunyi diRandom
objek. Ini adalah kebalikan dari transparansi referensial. Saya tidak mengerti klaim Anda bahwa "efek utama" tidak dapat menjadi efek samping. Dalam kode imperatif lebih umum daripada tidak bahwa efek utama adalah efek samping, karena program imperatif pada dasarnya bersifat stateful.Saya tidak tahu bagaimana fungsi-fungsi seperti itu disebut (atau apakah bahkan ada beberapa nama sistematis), tetapi saya akan memanggil fungsi yang tidak murni (karena jawaban lain meringkuk) tetapi selalu mengembalikan hasil yang sama jika disertakan dengan parameter yang sama "fungsinya parameter "(dibandingkan dengan fungsi parameternya dan beberapa keadaan lainnya). Saya menyebutnya fungsi saja, tetapi sayangnya ketika kita mengatakan "fungsi" dalam konteks pemrograman, kita bermaksud sesuatu yang tidak harus menjadi fungsi yang sebenarnya sama sekali.
sumber
Ini pada dasarnya tergantung pada apakah Anda peduli dengan kenajisan atau tidak. Jika semantik dari tabel ini adalah bahwa Anda tidak peduli berapa banyak entri yang ada, maka itu murni. Lain, itu tidak murni.
Atau dengan kata lain, itu baik-baik saja asalkan optimasi berdasarkan kemurnian tidak merusak semantik program.
Contoh yang lebih realistis adalah jika Anda mencoba men-debug fungsi ini dan menambahkan pernyataan logging. Secara teknis, penebangan adalah efek samping. Apakah log membuatnya tidak murni? Tidak.
sumber
Saya akan mengatakan bahwa hal terbaik untuk ditanyakan bukanlah bagaimana kita menyebutnya, tetapi bagaimana kita akan menganalisis sepotong kode. Dan pertanyaan kunci pertama saya dalam analisis semacam itu adalah:
Ini mudah untuk diilustrasikan dalam Haskell (dan kalimat ini hanya setengah lelucon). Contoh kasus "tidak" akan menjadi sesuatu seperti ini:
Dalam contoh ini tindakan yang kita ambil (mencetak garis
"I'm doubling some number"
) tidak berdampak pada hubungan antarax
dan hasilnya. Ini berarti kita dapat melakukan refactor dengan cara ini (menggunakanApplicative
kelas dan*>
operatornya), yang menunjukkan bahwa fungsi dan efeknya sebenarnya ortogonal:Jadi dalam kasus ini saya, secara pribadi, akan mengatakan bahwa ini adalah kasus di mana Anda dapat memfaktorkan fungsi murni. Banyak pemrograman Haskell tentang hal ini — mempelajari cara memfaktorkan bagian murni dari kode yang efektif.
Contoh dari jenis "ya", di mana bagian-bagian yang murni dan berpengaruh tidak ortogonal:
Sekarang, string yang Anda cetak tergantung pada nilai
x
. Namun, bagian fungsi (dikalikanx
dua), tidak bergantung pada efek sama sekali, jadi kita masih bisa memfaktorkannya:Saya bisa terus menguraikan contoh lain, tetapi saya harap ini cukup untuk menggambarkan poin yang saya mulai dengan: Anda tidak "menyebutnya" sesuatu, Anda menganalisis bagaimana bagian-bagian yang murni dan berpengaruh berhubungan dan faktor mereka ketika itu untuk keuntungan Anda.
Ini adalah salah satu alasan Haskell menggunakan
Monad
kelasnya secara luas. Monads (antara lain) adalah alat untuk melakukan analisis dan refactoring semacam ini.sumber
Fungsi yang dimaksudkan untuk menyebabkan efek samping sering disebut efektif . Contoh https://slpopejoy.github.io/posts/Effectful01.html
sumber