Hitung jika suatu fungsi murni

11

Sesuai Wikipedia:

Dalam pemrograman komputer, fungsi dapat digambarkan sebagai murni jika kedua pernyataan ini tentang fungsi ditahan: Fungsi selalu mengevaluasi nilai hasil yang sama mengingat nilai argumen yang sama. Nilai hasil fungsi tidak dapat bergantung pada informasi atau keadaan tersembunyi yang dapat berubah saat eksekusi program berlangsung atau antara berbagai eksekusi program, juga tidak dapat bergantung pada input eksternal dari perangkat I / O. Evaluasi hasil tidak menyebabkan efek samping atau keluaran yang dapat diamati secara semantik, seperti mutasi objek yang dapat berubah atau keluaran ke perangkat I / O.

Saya bertanya-tanya apakah mungkin untuk menulis fungsi yang menghitung apakah suatu fungsi murni atau tidak. Contoh kode dalam Javascript:

function sum(a,b) {
    return a+b;
}

function say(x){
    console.log(x);
}

isPure(sum) // True
isPure(say) // False
Oni
sumber
7
Ini mungkin kandidat untuk Computer Stack Exchange . Ini cenderung lebih ke bidang teori ("mungkin") daripada praktis dan desain ... Ini sedikit di luar ken saya.
... dan meskipun "mungkin" dan "teori" sangat mungkin ada jawaban nyata untuknya (cocok untuk tanya jawab) yang bahkan mungkin melibatkan bukti ... yang sekali lagi membawanya kembali ke dunia ilmu komputer .
Saya pikir Anda dapat menentukan apakah suatu fungsi murni dengan melihat jenis fungsi yang dipanggil dalam definisinya. Maksud saya, Anda dapat mendefinisikan kemurnian dengan induksi pada struktur fungsi.
Giorgio
7
Tidak mungkin dilakukan tanpa peretasan refleksi platform khusus. Jika suatu fungsi adalah kotak hitam, tidak ada percobaan yang dapat membuktikannya murni. Misalnya, jika ada sesuatu seperti if (rand(1000000)<2) return WRONG_ANSWER, menyelidiki fungsi berkali-kali untuk perilaku yang konsisten tidak akan membantu. Tetapi, jika Anda memiliki akses ke definisi fungsi, buktinya sepele.
SK-logic
1
@ user470365 Dari definisi fungsi murni - "Evaluasi hasil tidak menyebabkan efek samping atau keluaran yang dapat diamati secara semantik, seperti mutasi objek yang dapat berubah atau keluaran ke perangkat I / O." - Apa pun yang menulis ke IO tidak murni menurut definisi. Dalam contoh tersebut, saypanggilan console.logyang tidak saymurni juga tidak murni.

Jawaban:

17

Ya, itu mungkin, tergantung pada bahasanya.

Dalam JavaScript, Anda dapat mengetahui apakah suatu fungsi murni dengan kriteria berikut:

  • Hanya membaca parameter dan penduduk lokal;

  • Itu hanya menulis penduduk setempat;

  • Pada non-lokal, ini hanya memanggil fungsi murni;

  • Semua fungsi yang dipanggil secara implisit murni, misalnya toString,; dan

  • Itu hanya menulis properti lokal jika mereka tidak alias non-lokal.

Aliasing tidak dapat ditentukan dalam JavaScript dalam kasus umum, karena Anda selalu dapat mencari properti dari objek secara dinamis ( object["property"]). Asalkan Anda tidak pernah melakukan itu, dan Anda memiliki sumber seluruh program, maka saya pikir masalahnya mudah ditelusuri. Anda juga akan memerlukan informasi tentang fungsi asli mana yang memiliki efek samping, seperti console.logatau sebagian besar apa pun yang melibatkan DOM.

Istilah "murni" juga dapat menggunakan beberapa klarifikasi. Bahkan dalam bahasa pemrograman yang sangat, diketik secara statis, murni fungsional, di mana semua fungsi secara transparan transparan, suatu fungsi masih dapat gagal untuk diakhiri. Jadi ketika kita berbicara tentang id :: a -> a, apa yang sebenarnya kita katakan bukanlah:

Diberikan beberapa nilai tipe a, fungsi idmenghasilkan nilai tipe a.

Melainkan:

Mengingat beberapa nilai dari jenis a, fungsi idtidak tidak menghasilkan nilai yang tidak tipe a.

Karena implementasi yang valid idadalah error "Not implemented!". Seperti yang ditunjukkan oleh Peteris, nontotalitas ini dapat dilihat sebagai semacam ketidakmurnian. Koka adalah bahasa pemrograman fungsional — dengan sintaks yang dimodelkan pada JavaScript — yang dapat menyimpulkan kemungkinan efek seperti divergensi (nonterminasi), transparansi referensial, melempar pengecualian, dan tindakan I / O.

Jon Purdy
sumber
+1 - Diberikan jawaban oleh Peteris mendapat begitu banyak upvotes .....
mattnz
Saya kira Anda perlu menambahkan "Ini hanya memanggil fungsi murni" ke daftar kriteria.
Greg Hewgill
1
@GregHewgill: Tangkapan bagus. Saya memperbarui jawabannya. Tidak apa-apa menyebut fungsi bermutasi pada penduduk lokal, asalkan tidak ada efek sampingnya. Istilah "Murni" terlalu berlebihan ...
Jon Purdy
Anda juga perlu memeriksa apakah toStringmurni untuk objek yang Anda gunakan sebagai string.
Oleg V. Volkov
Saya tidak berpikir jawaban ini benar, karena hanya ada beberapa keadaan di mana Anda benar-benar dapat membuat penentuan ini. Pertimbangkan: apakah fungsi ini murni? function a (o) { return o.method(); }- kami tidak dapat menjawabnya, karena ini tergantung pada parameter apa oyang diteruskan. Selain itu, kami tidak dapat menjelaskan apa yang terjadi jika fungsi murni yang sebelumnya disertifikasi diubah menjadi implementasi yang tidak murni, yang selalu menjadi masalah potensial dengan javascript.
Jules
11

Tidak. Anda dapat dengan mudah memeriksa apakah suatu fungsi hanya melakukan operasi "murni-aman", seperti yang dijelaskan dalam jawaban Jon Purdy, tetapi itu IMO tidak cukup untuk menjawab pertanyaan.

Pertimbangkan fungsi ini:

function possiblyPure(x) {
    if (someCheck(x)) {
        return x+1; // pure code path
    }
    else {
        console.log("I'm so unpure..."); // unpure code path
    }
}

Jelas, jika someChecktidak pasti, demikian juga possiblyPure. Tetapi, jika someCheckmurni dan mengembalikan trueuntuk setiap nilai yang mungkin x, possiblyPureadalah murni, karena jalur kode tidak murni tidak dapat dijangkau!

Dan inilah bagian yang sulit: menentukan apakah someCheckmengembalikan benar untuk setiap input yang mungkin. Mencoba menjawab pertanyaan itu dengan segera membawa Anda ke ranah masalah terputus-putus dan masalah serupa yang belum diputuskan.

EDIT: Bukti bahwa itu tidak mungkin

Ada beberapa ketidakpastian apakah fungsi murni harus diakhiri pada setiap input yang mungkin. Tetapi dalam kedua kasus, masalah penghentian dapat digunakan untuk menunjukkan bahwa pemeriksaan kemurnian tidak mungkin.

Kasus A) Jika fungsi murni diperlukan untuk menghentikan setiap input yang mungkin, Anda harus menyelesaikan masalah penghentian untuk menentukan apakah fungsi tersebut murni atau tidak. Karena ini diketahui tidak mungkin, dengan definisi ini, kemurnian tidak dapat dihitung.

Kasus B) Jika fungsi murni dibolehkan untuk tidak berhenti pada beberapa input, kita dapat membangun sesuatu seperti itu: Mari kita asumsikan bahwa isPure(f)menghitung jika fadalah string yang mendefinisikan fungsi murni.

function halts(f) {
   var fescaped = f.replace(/\"/g, '\\"');
   var upf = 'function() { '+f+'("'+fescaped+'\); console.log("unpure"); }';
   return isPure(upf);
}

Sekarang isPureharus menentukan apakah fberhenti pada sumbernya sendiri sebagai input. Jika berhenti, upftidak murni; jika itu tidak berakhir, upfadalah murni iff fadalah murni.

Jika isPureberfungsi seperti yang diharapkan (mengembalikan hasil yang benar dan berakhir pada setiap input), kami akan menyelesaikan masalah penghentian (*)! Karena ini diketahui mustahil, isPuretidak bisa ada.

(*) untuk fungsi JavaScript murni, yang cukup untuk menyelesaikannya untuk mesin turing juga.

pengguna281377
sumber
3
Benar. Itu selalu mungkin untuk melakukan analisis konservatif - untuk memeriksa apakah suatu fungsi benar-benar murni, tetapi tidak mungkin untuk memeriksa apakah itu pasti tidak murni.
SK-logic
Banyak kasus dapat dianggap remeh - fungsi murni yang dijelaskan oleh Jon Purdy atau fungsi tidak murni yang tanpa syarat melakukan sesuatu yang kotor; tetapi secara umum, seseorang dapat membuat kasus-kasus yang tidak dapat diputuskan.
pengguna281377
1

Pertanyaan stackoverflow ini memiliki jawaban oleh yfeldblum yang relevan di sini. (Dan memiliki downvote untuk beberapa alasan saya tidak bisa mengerti. Apakah etiket buruk untuk memperbaiki sesuatu yang berusia 3 tahun?) Dia memberikan bukti bahwa apakah suatu fungsi murni dapat direduksi ke masalah penghentian dalam komentar.

Saya pikir dari sudut pandang praktis itu tidak akan terlalu sulit untuk beberapa bahasa jika Anda membiarkan fungsi kembali ya, tidak, atau mungkin. Saya menonton video tentang Clojure beberapa hari yang lalu, dan pembicara telah melakukan sejumlah contoh pengotor dalam basis kode dengan mencari sekitar 4 string yang berbeda (seperti "ref"). Karena penekanan Clojure pada kemurnian dan pemisahan hal-hal yang tidak murni, itu sepele, tetapi itu tidak persis apa yang Anda cari.

Jadi, secara teori tidak mungkin, secara praktis mungkin jika Anda mengubah sedikit pertanyaan, dan saya pikir betapa sulitnya akan sangat tergantung pada bahasa. Bahasa yang lebih sederhana / lebih bersih dengan fokus pada keabadian dan refleksi yang baik akan lebih mudah.

Michael Shaw
sumber
Saya rasa, itu telah diturunkan karena salah. bottomadalah nilai kelas pertama yang valid, tidak layak didiskriminasi dengan cara ini.
SK-logic
0

Pertanyaan yang bagus

Yang terbaik yang dapat Anda lakukan dalam praktik, dengan asumsi tidak ada kemampuan untuk mendengarkan tindakan i / o untuk memanggil fungsi sesering mungkin. Kemudian lihat apakah nilai kembali konsisten.

Tetapi Anda tidak dapat melakukan ini secara umum. Dapat diperdebatkan, program non-stop adalah non-murni, dan kami tidak dapat memutuskan masalah penghentian.

Peter adalah
sumber
1
-1: Akan sangat sepele untuk menulis fungsi yang lulus tes ini dan sama sekali tidak murni.
mattnz
3
Dengan logika ini, voidfungsi apa pun akan menjadi "murni", yang jelas-jelas salah.
Greg Hewgill
1
@Reg: Dengan ekstensi, void foo (void) juga harus murni.
mattnz
0

Tidak mungkin dalam kasus umum. Lihat menghentikan masalah . Secara singkat, tidak mungkin untuk menulis sebuah program yang, mengingat fungsi dan input yang berubah-ubah, menentukan apakah program tersebut akan berhenti atau berjalan selamanya. Jika berjalan selamanya, itu bukan fungsi murni yang sesuai dengan definisi yang Anda berikan.

dbkk
sumber
5
Menjalankan selamanya tampaknya tidak mengabaikan fungsi karena memenuhi kriteria untuk fungsi murni.
whatsisname
+1: Ada implisit yang diperlukan agar fungsi diakhiri oleh "Fungsi selalu mengevaluasi nilai hasil yang sama dengan yang diberikan ...."
mattnz
2
Secara konsisten berjalan selamanya tanpa mengubah keadaan apa pun adalah "murni" sempurna. Tapi, tentu saja, ini adalah masalah terminologi di sini.
SK-logic
@ mattnz, fungsi seperti itu akan selalu dievaluasi bottomnilainya.
SK-logic
1
Saya bisa melihat di mana masalah terminologi masuk. Dalam beberapa interpretasi, fungsi "murni" adalah fungsi yang deterministik serta tidak pernah mengkomunikasikan keadaan atau nilai apa pun dengan pihak luar selama pelaksanaannya. Dalam interpretasi lain, penghentian ditambahkan ke persyaratan. Dengan interpretasi pertama, mudah untuk menentukan apakah suatu fungsi murni: mesin yang mengeksekusi bahasa tertentu harus dapat menentukan apakah suatu program dalam bahasa itu melakukan komunikasi dengan pihak luar.
rwong