Katakanlah fn(x)
adalah fungsi murni yang melakukan sesuatu yang mahal, seperti mengembalikan daftar faktor utama x
.
Dan katakanlah kita membuat versi memoised dari fungsi yang sama yang disebut memoizedFn(x)
. Selalu mengembalikan hasil yang sama untuk input yang diberikan, tetapi tetap menyimpan cache pribadi dari hasil sebelumnya untuk meningkatkan kinerja.
Secara formal, memoizedFn(x)
dianggap murni?
Atau adakah nama lain atau istilah kualifikasi yang digunakan untuk merujuk fungsi semacam itu dalam diskusi KB? (Yaitu fungsi dengan efek samping yang dapat mempengaruhi kompleksitas komputasi panggilan berikutnya tetapi yang mungkin tidak mempengaruhi nilai kembali.)
terminology
pure-function
callum
sumber
sumber
funcx(){sleep(cached_time--); return 0;}
mengembalikan val yang sama setiap kali, tetapi akan tampil berbedaJawaban:
Iya. Versi memo dari fungsi murni juga merupakan fungsi murni.
Yang diperhatikan kemurnian fungsi hanyalah efek yang parameter input pada nilai balik fungsi (melewati input yang sama harus selalu menghasilkan output yang sama) dan efek samping apa pun yang relevan dengan status global (mis. Teks ke terminal atau UI atau jaringan) . Waktu komputasi dan penggunaan memori tambahan tidak relevan dengan fungsi kemurnian.
Tembolok dari fungsi murni hampir tidak terlihat oleh program; bahasa pemrograman fungsional diperbolehkan untuk secara otomatis mengoptimalkan fungsi murni ke versi memoized fungsi jika dapat menentukan bahwa itu akan bermanfaat untuk melakukannya. Dalam praktiknya, secara otomatis menentukan kapan memoisasi bermanfaat sebenarnya adalah masalah yang cukup sulit, tetapi optimasi seperti itu akan valid.
sumber
Wikipedia mendefinisikan "Fungsi Murni" sebagai fungsi yang memiliki properti berikut:
Its nilai kembali adalah sama untuk argumen yang sama (tidak ada variasi dengan variabel lokal statis, variabel non-lokal, argumen referensi bisa berubah atau masukan aliran dari perangkat I / O).
Evaluasi tidak memiliki efek samping (tidak ada mutasi variabel statis lokal, variabel non-lokal, argumen referensi yang dapat diubah atau aliran I / O).
Akibatnya, fungsi murni mengembalikan output yang sama dengan input yang sama, dan tidak memengaruhi apa pun di luar fungsi tersebut. Untuk tujuan kemurnian, tidak masalah bagaimana fungsi menghitung nilai kembalinya, asalkan mengembalikan output yang sama dengan input yang sama.
Bahasa murni yang berfungsi seperti Haskell secara rutin menggunakan memoisasi untuk mempercepat suatu fungsi dengan menyimpan hasil yang sebelumnya dihitung.
sumber
static const
variabel lokal dalam C ++ (tetapi bukan C), atau struktur data yang dievaluasi malas di Haskell. Ada satu syarat lagi yang Anda butuhkan: inisialisasi harus aman-utas.Ya, fungsi memoized murni biasanya disebut sebagai pure. Ini sangat umum dalam bahasa-bahasa seperti Haskell, di mana hasil memoise, dievaluasi malas, tidak berubah adalah fitur bawaan.
Ada satu peringatan penting: fungsi memoizing harus aman dari thread, atau Anda mungkin akan mendapatkan kondisi balapan ketika dua thread mencoba untuk memanggilnya.
Salah satu contoh ilmuwan komputer yang menggunakan istilah "murni fungsional" dengan cara ini adalah posting blog ini oleh Conal Elliott tentang memoisasi otomatis:
Ada banyak contoh dalam literatur peer-review, dan telah berlangsung selama beberapa dekade. Sebagai contoh, makalah ini dari tahun 1995, "Menggunakan Memoisasi Otomatis sebagai Alat Rekayasa Perangkat Lunak dalam Sistem AI Dunia Nyata," menggunakan bahasa yang sangat mirip di bagian 5.2 untuk menggambarkan apa yang sekarang kita sebut sebagai fungsi murni:
Beberapa bahasa imperatif memiliki idiom serupa. Misalnya,
static const
variabel dalam C ++ diinisialisasi hanya sekali, sebelum nilainya digunakan, dan tidak pernah bermutasi.sumber
Tergantung bagaimana Anda melakukannya.
Biasanya orang ingin menulis memo dengan mematikan semacam kamus cache. Ini memiliki semua masalah yang terkait dengan mutasi yang tidak murni, seperti harus khawatir tentang konkurensi, khawatir tentang cache yang tumbuh terlalu besar, dll.
Namun, Anda dapat memo tanpa mutasi memori yang tidak murni. Salah satu contoh adalah dalam jawaban ini , di mana saya melacak nilai-nilai yang di-memo secara eksternal melalui
lengths
argumen.Dalam tautan yang diberikan Robert Harvey , evaluasi malas digunakan untuk menghindari efek samping.
Teknik lain yang kadang-kadang terlihat adalah menandai memoisasi secara eksplisit sebagai efek samping yang tidak murni dalam konteks suatu
IO
tipe, seperti dengan fungsi memoisasi efek kucing .Yang terakhir ini memunculkan poin bahwa kadang-kadang tujuannya hanya merangkum mutasi daripada menghilangkannya. Sebagian besar programmer fungsional menganggapnya "cukup murni" untuk membuat pengotor eksplisit dan dienkapsulasi.
Jika Anda ingin istilah untuk membedakannya dari fungsi yang benar-benar murni, saya pikir itu cukup dengan hanya mengatakan "memoized dengan kamus yang bisa diubah." Itu membuat orang tahu bagaimana menggunakannya dengan aman.
sumber
collatz(100)
dancollatz(200)
untuk bekerja sama. Dan IIUIC, masalah dengan cache tumbuh terlalu besar tetap (meskipun Haskell mungkin punya beberapa trik bagus untuk ini?).IO
murni. Semua metode yang tidak murniIO
dan Kucing dinamaiunsafe
.Async.memoize
juga murni, jadi kita tidak harus puas dengan "cukup murni" :)Biasanya, fungsi yang mengembalikan daftar tidak murni sama sekali karena memerlukan alokasi penyimpanan dan dengan demikian dapat gagal (misalnya dengan melemparkan pengecualian, yang tidak murni). Bahasa yang memiliki tipe nilai dan dapat mewakili daftar sebagai tipe nilai ukuran-terikat mungkin tidak memiliki masalah ini. Karena alasan ini, teladan Anda mungkin tidak murni.
Secara umum, jika memoisasi dapat dilakukan dengan cara yang bebas kesalahan-kasus (mis. Dengan memiliki penyimpanan yang dialokasikan secara statis untuk hasil memo, dan sinkronisasi internal untuk mengontrol akses ke mereka jika bahasa mengakui utas), masuk akal untuk mempertimbangkan fungsi seperti itu murni.
sumber
Anda dapat menerapkan memoisasi tanpa efek samping menggunakan monad negara .
Dalam kasus Anda negara akan menjadi nilai memoized atau tidak sama sekali (yaitu Haskell
Maybe
atau ScalaOption[A]
). Jika nilai memoized hadir maka dikembalikan sebagaiA
, jikaA
tidak dihitung dan dikembalikan sebagai keadaan transisi dan hasilnya.sumber