Mengapa Today () merupakan contoh fungsi yang tidak murni?


38

Sepertinya, ketika membaca sesuatu seperti artikel Wikipedia ini tentang "fungsi murni" , mereka mendaftar Today()sebagai contoh fungsi tidak murni tetapi tampaknya cukup murni bagi saya. Apakah karena tidak ada argumen input formal? Mengapa waktu aktual hari tidak diperlakukan sebagai "input ke fungsi" dalam hal ini jika Anda memberikan input yang sama, yaitu dieksekusi today()dua kali pada waktu yang sama, atau melakukan perjalanan kembali pada waktu untuk mengeksekusinya kembali (mungkin hipotetis: )), output akan menjadi waktu yang sama. Today()tidak pernah memberi Anda nomor acak. selalu memberi Anda waktu sepanjang hari.

Artikel Wikipedia mengatakan "waktu yang berbeda akan menghasilkan hasil yang berbeda" tetapi itu seperti mengatakan untuk yang berbeda x sin(x)akan memberikan Anda rasio yang berbeda. Dan sin(x)merupakan contoh fungsi murni mereka.


8
Jika Anda melewati waktu siang hari, apa fungsinya?
JB King

1
Saya berharap itu memberi Anda waktu hari. (bukan fungsi yang paling berguna). Tetapi tidak ada argumen, yang saya pikir adalah akar dari jawabannya.
Brad

3
Bisakah Anda memprediksi hasilnya (berdasarkan parameter input yang Anda berikan)?
Daniel B

1
@ DanielB Tidak ada daya prediktif terhadap parameter input tidak ada / nol yang ternyata. Satu-satunya hal yang bisa saya lakukan adalah melihat jam tangan saya (jk ponsel saya).
Brad

"Mengapa waktu sebenarnya hari tidak diperlakukan sebagai" input ke fungsi "" Ini, pada dasarnya, adalah masalah yang coba dipecahkan oleh monad. Fungsi murni hanya dapat didasarkan pada input mereka & tidak dapat memiliki efek samping. Jika Anda menjadikan "keadaan dunia sebelum saya" sebagai input dan "keadaan dunia setelah saya" sebagai bagian dari nilai pengembalian & melewati negara-negara dunia ini melalui program Anda, sekali lagi Anda dapat menjadi murni.
Sean McSomething

Jawaban:


103

Apakah karena tidak ada argumen input formal?

Itu karena output tergantung pada sesuatu yang bukan input, yaitu waktu saat ini.

Mengapa waktu sebenarnya hari tidak diperlakukan sebagai "input ke fungsi"

Karena Anda tidak meneruskannya sebagai parameter. Jika Anda mengirimkannya sebagai parameter, fungsi tersebut akan menjadi fungsi identitas pada tanggal, yang sangat tidak berguna. Seluruh titik Today()fungsi adalah untuk mengeluarkan sesuatu yang bergantung pada nilai eksternal dan waktu yang terus berubah.

Keuntungan dari fungsi murni adalah bahwa perilaku mereka benar-benar dapat direproduksi dan deterministik, sehingga mudah untuk memiliki bukti formal dan jaminan keras. Mereka selalu melakukan hal yang sama. Today()hampir kebalikannya: selalu (memungkinkan granularitas waktu) melakukan sesuatu yang berbeda.


2
Jadi meskipun waktu realitas adalah semacam input, karena itu tidak diberikan sebagai input dan itu di luar kendali fungsi (baik secara internal ke fungsi dan di luar kendali siapa pun yang menelepon Today()) Today()menjadi tidak murni. The Today()fungsi mungkin sedikit contoh konyol. Lebih tepat mungkin beberapa Count()fungsi. Mengingat jumlah item yang sama untuk dihitung Count()akan selalu mengembalikan nomor yang sama, tetapi karena itu di luar ruang lingkup Count()itu tidak murni.
Brad

1
@brad itu agak abu-abu - ada argumen aktual implisit - array atau daftar. Diberikan daftar yang tidak berubah dan argumen yang sama setiap kali akan selalu mengembalikan nilai yang sama.
Maks

34
"waktu realitas adalah semacam input" - ya; memang, negara global secara implisit tersedia (yaitu 'semacam input') untuk semua fungsi, tetapi jika mereka bergantung padanya untuk hasil mereka tidak murni!
AakashM

4
@Brad count()pada sebagian besar bahasa pemrograman jelas murni. Ini memiliki nilai input eksplisit: koleksi yang jumlah yang Anda inginkan. Jangan bingung dengan sintaksis seperti myCollection.count(); itu hanya gula count(myCollection).
Andres F.

Jawaban bagus seperti biasa, tetapi tidak secara eksplisit mencakup variabel bebas yang tidak dapat diubah. Mereka bukan input ke fungsi - tidak lulus sebagai parameter - tetapi fungsi tergantung pada mereka bahkan jika itu masih transparan secara referensi.

24

sin(x)akan selalu mengembalikan nilai yang sama, selama xtetap sama. Today()dapat mengembalikan hasil yang berbeda dari waktu ke waktu karena itu tergantung pada nilai di luar kendali Anda . Misalnya, jika sesuatu di luar kendali program Anda mengubah internal sistem $current_datetime saat program Anda berjalan, Today()tiba-tiba akan menghasilkan hasil yang berbeda.


"akan selalu mengembalikan nilai yang berbeda" sedikit ... kata-kata yang tidak murni . Wikipedia mengatakan "mengembalikan hari ini dalam seminggu" yang berarti bahwa nilai yang diperoleh pada hari Senin tidak akan berbeda
agas

7
@gnat: Benar, kecuali jika sesuatu di luar program Anda mengubah kalender internal komputer Anda sehingga tiba-tiba mengira itu hari Kamis. Maka panggilan Today()akan kembali "Kamis" pada hari Senin.
FrustratedWithFormsDesigner

3
@gnat Yah, itu tidak akan selalu mengembalikan nilai yang berbeda (hampir tidak ada fungsi berguna yang melakukannya). Tetapi, seperti kebanyakan fungsi tidak murni, nilai kembali dapat bervariasi bahkan selama eksekusi satu program (misalnya, jika berjalan semalam).

3
@delnan: Ya, itu adalah kutukan dari penulis skrip database naif! : P "Tapi BAGAIMANA itu bisa melewatkan 300 catatan? Naskah bekerja dengan baik ketika saya mengujinya kemarin pagi!"
FrustratedWithFormsDesigner

@nannan itu sudah pasti. Saya hanya menunjukkan bahwa menggunakan selalu dalam kata-kata awal (dikoreksi dalam jawaban versi saat ini untuk bisa ) agak tidak tepat
nyamuk

13

Today () adalah fungsi yang tidak murni karena hasilnya tergantung pada sesuatu yang tidak Anda berikan; khususnya, waktu sistem saat ini. Oleh karena itu, hasilnya tidak deterministik ketika hanya didasarkan pada input yang diberikan saat doa.

Fungsi murni akan menjadi int Add(int a, int b) {return a + b;}. Fungsi ini hanya berfungsi dengan apa yang diberikan, dan tidak menggunakan data keadaan eksternal lainnya. Hasil alami dari ini adalah Anda dapat Add(2,2)dan mendapatkan 4 dari sekarang hingga akhir waktu. Selain itu, karena fungsi tidak mengubah keadaan eksternal (tidak memiliki "efek samping"), Tambahkan () dari 2 dan 2 dari sekarang sampai akhir waktu tidak akan mengubah hal lain dalam sistem, kecuali jika Anda kemudian tetapkan hasil fungsi ke variabel atau gunakan nilai untuk memperbarui status (yang bukan operasi yang dilakukan oleh fungsi itu sendiri). Hampir semua operasi matematika klasik adalah fungsi murni dan dapat diimplementasikan seperti itu.

Today (), di sisi lain, dapat menghasilkan nilai yang sama ketika dipanggil dua kali berturut-turut, tetapi tidak jika dipanggil berulang kali selama beberapa hari. Ini karena itu tergantung pada data keadaan eksternal yang tidak Anda berikan sebagai parameter untuk fungsi tersebut. Akibatnya, tidak mungkin, dalam batas-batas program, untuk mengontrol hasil fungsi Today (). Ini akan menghasilkan nilai yang diberikan pada hari tertentu, dan tidak akan pernah menghasilkan nilai itu pada hari lain, kecuali jika Anda mengubah jam sistem komputer yang menjalankannya (perubahan umumnya terjadi di luar batas-batas program).

Fungsi yang tidak murni tidak selalu merupakan hal yang buruk; fungsi yang tidak murni diperlukan, bahkan dalam bahasa fungsional, untuk berinteraksi dengan apa pun di luar batas program, seperti penyimpanan data, saluran komunikasi, tampilan UI, perangkat periferal, dll. Program yang tidak melakukan hal-hal ini adalah program yang sangat terbatas dalam kegunaannya; Saya bahkan akan menyebut program seperti itu sepele, karena tanpa sarana untuk menerima input atau jalan apa pun untuk memberi tahu Anda tentang hasilnya, mungkin juga tidak melakukan apa-apa. Program yang ditulis dalam bahasa fungsional hanya dapat memiliki input yang disediakan oleh runtime dan menghasilkan output yang dilaporkan ke runtime tanpa ada metode yang tidak murni, tetapi itu karena runtime sedang mengabstraksi semua detail yang tidak murni dari pekerjaan dalam sistem komputer yang tidak sempurna,

Ini hanyalah Hal yang Sangat Baik untuk mengetahui fungsi mana yang Anda gunakan yang murni dan mana yang tidak, sehingga Anda dapat membuat keputusan yang baik tentang bagaimana mereka digunakan. Fungsi yang tidak murni, karena mereka melakukan hal-hal atau bergantung pada hal-hal yang tidak terlihat dari penggunaannya, dapat berperilaku tidak terduga dengan hanya diberi pengetahuan tentang penggunaannya. Pengetahuan lebih lanjut tentang tujuan fungsi, dan dengan demikian apa yang dibutuhkannya dari atau lakukan untuk keadaan eksternal, diperlukan untuk menempatkan suatu sistem yang menggunakannya dalam keadaan konsisten dan dengan demikian mengharapkan hasil deterministik.


8

Tampaknya cukup jelas bahwa fungsi ini gagal dalam tes kemurnian pertama yang diberikan pada awal halaman itu:

  1. Fungsi selalu mengevaluasi nilai hasil yang sama dengan nilai argumen yang sama. Nilai hasil fungsi tidak dapat bergantung pada informasi atau keadaan tersembunyi yang dapat berubah saat eksekusi program berlangsung atau antara eksekusi program yang berbeda, juga tidak dapat bergantung pada input eksternal dari perangkat I / O.

Perhatikan bahwa karena tidak memerlukan argumen, hanya ada satu set nilai argumen yang mungkin - set kosong. Dan fungsi ini dapat dan tidak mengembalikan hasil yang berbeda untuk 'nilai argumen' yang sama '.

Selanjutnya, fungsi nilai hasil tidak tergantung pada "tersembunyi ... negara yang dapat berubah sebagai hasil eksekusi program". Jadi kegagalan lain.


@ JörgWMittag Saya tidak yakin di mana saya menyatakan bahwa fungsi tanpa argumen tidak dapat mengembalikan nilai.
AakashM

Kentut otak. Saya membaca "hanya ada satu set nilai pengembalian yang mungkin ".
Jörg W Mittag

8

() => 1akan menjadi fungsi murni, karena selalu mengembalikan 1. Today()dapat mengembalikan "Senin" atau "Selasa" atau hampir semua nilai lainnya.

Cara lain untuk memikirkannya adalah fungsi murni tidak bergantung pada negara. Dunia biasanya dianggap sebagai negara. Anda perlu mengetahui keadaan realitas untuk mengetahui hari apa hari ini.

Namun Anda tidak perlu tahu sesuatu yang istimewa tentang keadaan dunia untuk mengetahui apa sin(x)itu. Dan panggilan sin(x)untuk diberikan xakan mengembalikan nilai yang sama.


Wikipedia mengatakan "mengembalikan hari ini dalam seminggu", yang berarti ia dapat kembali Senin, Selasa dll tetapi tidak "1/23/2013" atau "1/24/2013"
gnat

7
@gnat: Diperbarui, tetapi perbedaannya tidak terlalu penting.
Guvante

2

Date(timestamp)akan menjadi fungsi murni. Karena idempotensinya. Dan karena tidak akan ada efek samping.

Today()dapat memvariasikan hasilnya tergantung pada kapan Anda memanggilnya. Itulah yang membuatnya tidak murni. Itu bukan idempoten. Meskipun tidak memiliki efek samping, tetapi itu tidak membuatnya murni.


2

Berikut adalah kode pseudo kecil yang saya pikirkan ketika membahas fungsi murni

newValue = Function();
while(true)
{
   oldValue = newValue;
   newValue = Function();
   assert( newValue == oldValue );
}

Jika itu berjalan tanpa batas waktu dan tidak pernah dapat memicu pernyataan, itu adalah fungsi murni. Lebih dari itu, jika Anda memiliki fungsi yang menggunakan args, maka sedikit modifikasi ....

oldValue = Function( importantVariableToYourApp );
newValue = Function( importantVariableToYourApp );
assert( newValue == oldValue );

Jika Anda dapat menggunakannya setelah setiap penugasan variabel di aplikasi Anda, dan itu tidak mengubah hasil dalam aplikasi Anda, dan itu tidak pernah dapat gagal menegaskan, maka itu adalah fungsi murni.


2

Pertama, tidak ada yang namanya fungsi tanpa argumen (atau array tanpa indeks atau peta tanpa kunci). Ini adalah karakteristik yang menentukan fungsi untuk memetakan satu atau lebih nilai argumen ke nilai lain.

Karenanya, todaysama sekali bukan fungsi sama sekali, karenanya tidak ada fungsi murni. Atau kita dapat menginterpretasikan sintaks

today()

sedikit sehingga artinya

today   ()      -- today, applied to the value ()

Di Haskell, misalnya, ini akan valid:

data Day = Mon | Tue | Wed | Thu | Fri | Sat | Sun deriving Show
today :: () -> Day
today () = ....?
main = print (today())

karena ada tipe () dengan nilai tunggal ().

Pertanyaannya hanya, bagaimana bisa todaymenghitung hari dalam seminggu, jika hanya memiliki ()? Tidak mungkin tanpa membaca pengatur waktu sistem, secara langsung atau melalui fungsi pembantu yang tidak murni.

Timer sistem adalah contoh yang sangat baik untuk keadaan global.


1

Masalahnya today()adalah ia dapat menghasilkan hasil yang berbeda jika dipanggil dua kali atau lebih dalam suatu fungsi.

Berikut adalah contoh kode, yang dapat memperkenalkan bug.

function doSomething(when)
{
     if(today() == when)
     {
           // open a resource or create a temp file.....
     }

     // do some other work

     if(today() == when)
     {
           // close the resource or delete temp file.....
     }
}

Itu mungkin dalam contoh di atas. Bahwa ifpernyataan kedua tidak akan dieksekusi. Bahkan jika yang pertama melakukannya. Meninggalkan sumber daya dalam kondisi buruk.


1

Untuk menjadi fungsi murni, memberikan parameter yang sama harus memberikan hasil yang sama setiap saat.

Setiap kali kami menelepon Today(), kami memberikan parameter yang sama (tidak ada), namun belum tentu mendapatkan hasil yang sama (Senin, Selasa, dll.).


4
ini sepertinya hanya mengulangi poin yang dibuat dan dijelaskan dalam jawaban teratas yang diposting sekitar dua tahun lalu. Hampir tidak layak menabrak pertanyaan berusia dua tahun dengan konten seperti itu
nyamuk

1
Saya tidak terlalu terbiasa dengan cara kerja stackexchange, tapi saya pikir karena ini adalah pertanyaan utama yang sudah ditabrak. Sejauh membuat poin berulang, saya ingat membaca meta bahwa bisa bermanfaat untuk memiliki beberapa jawaban yang serupa. Saya merasa milik saya ringkas dan berpotensi membantu.
Zantier
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.