Apa manfaat transparansi referensial bagi seorang programmer?

18

Dalam pemrograman, apa manfaat transparansi referensial ?

RT membuat salah satu perbedaan utama antara paradigma fungsional dan imperatif, dan sering digunakan oleh pendukung paradigma fungsional sebagai keuntungan yang jelas dibandingkan paradigma imperatif; tetapi dalam semua upaya mereka, para advokat ini tidak pernah menjelaskan mengapa itu bermanfaat bagi saya sebagai seorang programmer .

Tentu, mereka akan memiliki penjelasan akademis tentang seberapa "murni" dan "elegan" itu, tetapi bagaimana cara membuatnya lebih baik daripada kode yang kurang "murni"? Apa manfaatnya bagi saya dalam pemrograman sehari-hari saya?

Catatan: Ini bukan duplikat dari Apa itu transparansi referensial? Yang terakhir membahas topik apa itu RT, sementara pertanyaan ini menekankan manfaatnya (yang mungkin tidak begitu intuitif).

Eyal Roth
sumber
Terkait: stackoverflow.com/questions/210835/…
meriton - mogok pada
3
Transparansi referensial memungkinkan Anda menggunakan penalaran yang sama untuk: 1) Membuktikan properti kode dan 2) menulis program. Ada beberapa buku tentang Haskell di mana penulis harus bagaimana Anda bisa mulai dari beberapa persamaan yang Anda ingin fungsi terpenuhi dan menggunakan hanya alasan rasional Anda akhirnya mendapatkan implementasi dari fungsi tersebut, yang, karenanya, tentu saja benar. Sekarang seberapa banyak ini dapat diterapkan dalam pemrograman "sehari-hari" mungkin tergantung pada konteksnya ...
Bakuriu
2
@ er Apakah Anda menyukai kode yang lebih mudah untuk di-refactor karena Anda tahu apakah memanggil fungsi dua kali sama dengan menyimpan nilainya dalam suatu variabel, lalu menggunakan variabel tersebut dua kali? Apakah Anda mengatakan itu bermanfaat untuk pemrograman sehari-hari Anda?
Andres F.
Manfaatnya adalah Anda tidak perlu membuang waktu untuk memikirkan transparansi dan transparansi. Agak suka bagaimana manfaat dari variabel adalah bahwa Anda tidak perlu membuang waktu untuk memikirkan alokasi register.
user253751

Jawaban:

37

Manfaatnya adalah fungsi murni membuat kode Anda lebih mudah untuk dipikirkan. Atau, dengan kata lain, efek samping meningkatkan kompleksitas kode Anda.

Ambil contoh computeProductPricemetode.

Metode murni akan meminta Anda untuk kuantitas produk, mata uang, dll. Anda tahu bahwa setiap kali metode dipanggil dengan argumen yang sama, itu akan selalu menghasilkan hasil yang sama.

  • Anda bahkan dapat menyimpannya dan menggunakan versi yang di-cache.
  • Anda dapat membuatnya malas dan menunda panggilannya saat Anda benar-benar membutuhkannya, mengetahui bahwa nilainya tidak akan berubah sementara itu.
  • Anda dapat memanggil metode ini beberapa kali, karena tahu bahwa itu tidak akan memiliki efek samping.
  • Anda dapat berargumen tentang metode itu sendiri dalam isolasi dari dunia, mengetahui bahwa semua yang dibutuhkan adalah argumen.

Metode non-murni akan lebih kompleks untuk digunakan dan debug. Karena itu tergantung pada keadaan variabel selain argumen dan mungkin mengubahnya, itu berarti bahwa itu dapat menghasilkan hasil yang berbeda ketika dipanggil beberapa kali, atau tidak memiliki perilaku yang sama ketika tidak dipanggil sama sekali atau dipanggil terlalu cepat atau terlambat.

Contoh

Bayangkan ada metode dalam kerangka kerja yang mem-parsing angka:

decimal math.parse(string t)

Itu tidak memiliki transparansi referensial, karena itu tergantung pada:

  • Variabel lingkungan yang menentukan sistem penomoran, yaitu Basis 10 atau sesuatu yang lain.

  • Variabel dalam mathpustaka yang menentukan ketepatan angka untuk diuraikan. Jadi dengan nilai 1, parsing "12.3456"akan memberikan string 12.3.

  • Budaya, yang mendefinisikan pemformatan yang diharapkan. Misalnya, dengan fr-FR, parsing "12.345"akan memberi 12345, karena karakter pemisahan seharusnya ,, bukan.

Bayangkan betapa mudah atau sulitnya bekerja dengan metode seperti itu. Dengan input yang sama, Anda dapat memiliki hasil yang sangat berbeda tergantung pada saat Anda memanggil metode, karena sesuatu, di suatu tempat mengubah variabel lingkungan atau beralih budaya atau mengatur presisi yang berbeda. Karakter non-deterministik dari metode ini akan menyebabkan lebih banyak bug dan lebih banyak mimpi buruk debugging. Memanggil math.parse("12345")dan memperoleh 5349sebagai jawaban karena beberapa kode paralel menguraikan angka oktal tidak baik.

Bagaimana cara memperbaiki metode yang jelas-jelas rusak ini? Dengan memperkenalkan transparansi referensial. Dengan kata lain, dengan menyingkirkan keadaan global, dan memindahkan semuanya ke parameter metode:

decimal math.parse(string t, base=10, precision=20, culture=cultures.en_us)

Sekarang metodenya murni, Anda tahu bahwa tidak peduli kapan Anda memanggil metode, itu akan selalu menghasilkan hasil yang sama untuk argumen yang sama.

Arseni Mourzenko
sumber
4
Hanya tambahan: transparansi referensial berlaku untuk semua ekspresi dalam bahasa, bukan hanya fungsi.
Gardenhead
3
Perhatikan bahwa ada batasan seberapa transparan Anda. Membuat packet = socket.recv()transparan referensial agak mengalahkan titik fungsi.
Tandai
1
Harus budaya = budaya. Kecuali Anda ingin secara tidak sengaja membuat perangkat lunak yang hanya berfungsi dengan baik di AS.
user253751
@immibis: hm, pertanyaan bagus. Untuk apa aturan penguraian invariant? Entah mereka sama dengan en_us, dalam hal ini, mengapa repot, atau mereka berkorespondensi dengan negara lain, dalam hal ini, yang mana dan mengapa yang ini bukannya en_us, atau mereka memiliki aturan khusus yang tidak cocok dengan negara mana pun , yang tidak akan berguna. Tidak ada "jawaban sejati" antara 12,345.67dan 12 345,67: "aturan default" apa pun akan berfungsi untuk beberapa negara, dan tidak akan berfungsi untuk negara lain.
Arseni Mourzenko
3
@ArseniMourzenko Secara umum ini merupakan "common denominator terendah" dan mirip dengan sintaksis yang digunakan banyak bahasa pemrograman (yang juga invarian budaya). 12345diuraikan sebagai 12345, 12 345atau 12,345atau 12.345ada kesalahan. 12.345diurai sebagai angka floating-point yang tidak berubah selalu menghasilkan 12,345, sesuai dengan konvensi bahasa pemrograman menggunakan. sebagai pemisah desimal. String diurutkan berdasarkan titik kode Unicode dan case-sensitive. Dan seterusnya.
user253751
11

Apakah Anda sering menambahkan titik istirahat ke titik dalam kode Anda dan menjalankan aplikasi di debugger untuk mengetahui apa yang terjadi? Jika ya, itu sebagian besar karena Anda tidak menggunakan transparansi referensial (RT) dalam desain Anda. Jadi harus menjalankan kode untuk mengetahui fungsinya.

Inti dari ke RT adalah bahwa kodenya sangat deterministik, yaitu Anda dapat membaca kodenya dan mencari tahu apa yang dilakukannya, setiap saat, untuk rangkaian input yang sama. Setelah Anda mulai menambahkan dalam variabel yang bermutasi, beberapa di antaranya memiliki cakupan di luar fungsi tunggal, Anda tidak bisa hanya membaca kode. Kode tersebut harus dijalankan, baik di kepala Anda atau di debugger, untuk mengetahui cara kerjanya.

Kode yang lebih sederhana adalah membaca dan bernalar, semakin mudah untuk memelihara dan menemukan bug, sehingga menghemat waktu dan uang untuk Anda dan majikan Anda.

David Arno
sumber
10
"Setelah Anda mulai menambahkan dalam variabel bermutasi, beberapa di antaranya memiliki fungsi di luar satu, Anda tidak bisa hanya membaca kode, Anda harus menjalankannya, baik di kepala Anda atau di debugger, untuk mengetahui cara kerjanya. ": Poin bagus. Dengan kata lain, transparansi referensial tidak hanya berarti bahwa sepotong kode akan selalu menghasilkan hasil yang sama untuk input yang sama, tetapi juga bahwa hasil yang dihasilkan adalah satu - satunya efek dari potongan kode itu, bahwa tidak ada sisi tersembunyi lainnya. Efek seperti mengubah beberapa variabel yang telah didefinisikan jauh di modul lain.
Giorgio
Itu poin yang bagus. Saya memang memiliki sedikit masalah dengan kode yang lebih sederhana untuk dibaca / argumen alasan , karena lebih mudah untuk membaca atau alasan adalah atribut kode yang agak kabur dan subyektif.
Eyal Roth
Setelah Anda mulai menambahkan dalam variabel bermutasi, beberapa di antaranya memiliki cakupan di luar fungsi tunggal tetapi mengapa operasi penugasan tidak disarankan bahkan ketika lingkup variabel lokal untuk berfungsi?
rahulaga_dev
9

Orang-orang membuang istilah "lebih mudah untuk dipikirkan," tetapi tidak pernah menjelaskan apa artinya itu. Perhatikan contoh berikut:

result1 = foo("bar", 12)
// 100 lines of code
result2 = foo("bar", 12)

Apakah result1dan result2sama atau berbeda? Tanpa transparansi referensial, Anda tidak tahu. Anda harus benar-benar membaca isi dari foountuk memastikan, dan mungkin isi dari setiap fungsi foomemanggil, dan sebagainya.

Orang-orang tidak menyadari beban ini karena mereka terbiasa dengan itu, tetapi jika Anda bekerja di lingkungan yang murni fungsional selama satu atau dua bulan kemudian kembali, Anda akan merasakannya, dan itu adalah masalah besar .

Ada begitu banyak mekanisme pertahanan yang dilakukan orang untuk mengatasi kurangnya transparansi referensial. Sebagai contoh kecil saya, saya mungkin ingin result1mengingat-ingat, karena saya tidak akan tahu apakah itu akan berubah. Kemudian saya memiliki kode dengan dua status: sebelum result1disimpan dan sesudahnya. Dengan transparansi referensial, saya bisa menghitung ulang dengan mudah, asalkan perhitungan ulang tidak memakan waktu.

Karl Bielefeldt
sumber
1
Anda menyebutkan bahwa transparansi referensial memungkinkan Anda untuk mempertimbangkan hasil panggilan ke foo () dan mengetahui apakah result1dan result2itu sama. Aspek penting lainnya adalah bahwa jika foo("bar", 12)transparan referensial, maka Anda tidak perlu bertanya pada diri sendiri apakah panggilan ini telah menghasilkan beberapa efek di tempat lain (mengatur beberapa variabel? Menghapus file? Apa pun).
Giorgio
Satu-satunya "integritas referensial" yang saya kenal melibatkan basis data relasional.
Tandai
1
@ Markus Ini salah ketik. Karl berarti transparansi referensial, seperti yang terlihat jelas dari sisa jawabannya.
Andres F.
6

Saya akan mengatakan: transparansi referensial tidak hanya baik untuk pemrograman fungsional tetapi untuk semua orang yang bekerja dengan fungsi karena mengikuti prinsip paling tidak heran.

Anda memiliki fungsi dan dapat memberi alasan yang lebih baik tentang apa yang dilakukannya karena tidak ada faktor eksternal yang perlu Anda perhitungkan, karena input yang diberikan output akan selalu sama. Bahkan dalam bahasa imperatif saya, saya mencoba mengikuti paradigma ini sebanyak mungkin, hal berikutnya yang pada dasarnya secara otomatis mengikuti dari ini adalah: fungsi-fungsi kecil yang mudah dimengerti daripada fungsi-fungsi garis 1000+ mengerikan yang terkadang saya jalankan.

Fungsi-fungsi besar itu melakukan sihir dan saya takut menyentuhnya karena mereka dapat pecah dengan cara yang spektakuler.

Jadi fungsi murni bukan hanya untuk pemrograman fungsional, tetapi untuk setiap program.

Pieter B
sumber