Penanganan untuk mengimplementasikan operasi pada struktur data yang ditautkan ganda atau melingkar dalam bahasa dengan data yang tidak dapat diubah


11

Saya ingin belajar cara membuat grafik dan melakukan beberapa operasi lokal pada mereka di Haskell, tetapi pertanyaannya tidak spesifik untuk Haskell, dan alih-alih grafik kita dapat mempertimbangkan daftar yang ditautkan ganda.

Pertanyaan: Apa yang akan menjadi cara idiomatis atau yang direkomendasikan untuk menerapkan daftar yang ditautkan ganda (atau struktur data ganda yang ditautkan ganda) dan operasinya dalam bahasa yang terutama mendukung dan mengadvokasi untuk struktur data yang tidak dapat diubah (Haskell, Clojure, dll.) ? Secara khusus, bagaimana cara menggunakan pembaruan di tempat, yang secara resmi dilarang oleh bahasa tersebut?

Saya dapat dengan mudah membayangkan bahwa jika beberapa operasi lokal dilakukan pada daftar yang ditautkan ganda (jika item dimasukkan, misalnya), mungkin tidak perlu menyalin seluruh daftar segera karena kemalasan bahasa. Namun, karena daftar ini ditautkan dua kali lipat, jika dimodifikasi di satu tempat, tidak ada node lama yang dapat digunakan dalam versi baru daftar, dan mereka perlu ditandai, disalin, dikumpulkan dengan cepat atau lambat . Jelas ini adalah operasi yang berlebihan jika hanya salinan daftar yang diperbarui yang akan digunakan, tetapi mereka akan menambahkan "overhead" sebanding dengan ukuran daftar.

Apakah ini berarti bahwa untuk tugas-tugas seperti itu data yang tidak dapat diubah sama sekali tidak sesuai, dan bahasa deklaratif fungsional tanpa dukungan "asli" untuk data yang dapat berubah tidak sebagus yang imperatif? Atau, adakah solusi yang rumit?

PS Saya telah menemukan beberapa artikel dan presentasi mengenai hal ini di Internet tetapi mengalami kesulitan untuk mengikutinya, sementara saya berpikir bahwa jawaban untuk pertanyaan ini tidak boleh lebih dari satu paragraf dan mungkin diagram ... Maksud saya, jika ada tidak ada solusi "fungsional" untuk masalah ini, jawabannya mungkin adalah "gunakan C". Jika ada, maka seberapa rumitkah itu?


Pertanyaan-pertanyaan Terkait

  • + Msgstr "Struktur data dalam pemrograman fungsional" . Pertanyaan khusus saya tentang menggunakan pembaruan di tempat alih-alih alternatif yang tidak efisien tidak dibahas di sana.

  • "Mutasi Internal Struktur Data Persisten" . Di sana penekanannya tampaknya pada implementasi tingkat rendah dalam bahasa yang tidak ditentukan, sementara pertanyaan saya adalah tentang pilihan bahasa yang tepat (fungsional atau sebaliknya) dan tentang kemungkinan solusi idiomatik dalam bahasa fungsional.


Kutipan yang relevan

Bahasa pemrograman yang murni fungsional memungkinkan banyak algoritma untuk diekspresikan dengan sangat singkat, tetapi ada beberapa algoritma di mana keadaan yang dapat diupdate tampaknya memainkan peran penting. Untuk algoritma ini, bahasa murni fungsional, yang tidak memiliki status yang dapat diupdate, tampaknya secara inheren tidak efisien ( [Ponder, McGeer dan Ng, 1988] ).

- John Launchbury dan Simon Peyton Jones, thread status fungsional Lazy (1994), juga John Launchbury dan Simon Peyton Jones, State in Haskell (1995). Makalah ini memperkenalkan STkonstruktor tipe monadik di Haskell.


4
Direkomendasikan: Okasaki
Robert Harvey

2
Terima kasih untuk referensi. Saya sudah menemukan tesisnya .
Alexey

Makalah ini terlihat menjanjikan: Lazy depth-first search dan algoritma grafik linear di Haskell (1994), oleh David King dan John Launchbury.
Alexey

Sepertinya masalah yang sama dengan array ditangani oleh paket diffarray yang mengimplementasikan DiffArraytipe. Melihat sumber dari diffarray paket, saya melihat 91 kejadian unsafePerformIO. Sepertinya jawaban untuk pertanyaan saya adalah "ya, tidak, bahasa murni fungsional dengan data tidak dapat diubah tidak cocok untuk menerapkan algoritma yang biasanya mengandalkan pembaruan di tempat".
Alexey

Solusi saya saat ini (di Haskell) adalah dengan menggunakan kamus ( Map, IntMap, atau HashMap) sebagai storage dan untuk membuat node berisi ID dari node terkait. "Semua masalah dalam ilmu komputer dapat diselesaikan dengan tingkat tipuan yang lain."
Alexey

Jawaban:


6

Mungkin ada struktur data abadi yang efisien lainnya yang sesuai dengan tugas khusus Anda, tetapi tidak umum seperti daftar yang ditautkan dua kali lipat (yang sayangnya rentan terhadap bug modifikasi bersamaan karena mutabilitasnya). Jika Anda menentukan masalah Anda dengan lebih sempit, struktur seperti itu mungkin dapat ditemukan.

Jawaban umum untuk (relatif) melintasi ekonomi dari struktur yang tidak berubah adalah lensa. Idenya adalah bahwa Anda dapat menyimpan informasi yang cukup untuk merekonstruksi struktur berubah yang dimodifikasi dari bagian yang tidak dimodifikasi dan bagian yang saat ini dimodifikasi, dan menavigasi ke node tetangga.

Struktur lain yang bermanfaat adalah ritsleting . (Bagian yang lucu adalah bahwa tanda tangan jenis untuk ritsleting lensa adalah turunan sekolah-matematika dari tanda tangan jenis struktur.)

Berikut ini beberapa tautan.


1
tergantung pada apa yang dibutuhkan ritsleting mungkin juga berguna
jk.

Untuk menentukan masalah saya secara lebih sempit, misalkan saya ingin memprogram sistem penulisan ulang grafik, misalnya evaluator kalkulus lambda berdasarkan penulisan ulang grafik.
Alexey

1
@ Alexey: Apakah Anda terbiasa dengan pekerjaan Clean people pada penulisan ulang grafik? wiki.clean.cs.ru.nl/…
Giorgio

1
@Alexey: Bukannya saya tahu: Bersih adalah sepupu dari Haskell yang dikembangkan sendiri. Ini juga memiliki mekanisme yang berbeda untuk menangani efek samping (AFAIK disebut tipe unik). Di sisi lain, para pengembang telah banyak bekerja dengan penulisan ulang grafik. Jadi mereka bisa menjadi orang-orang terbaik yang tahu tentang penulisan ulang grafik dan pemrograman fungsional.
Giorgio

1
Saya setuju bahwa ritsleting tampaknya dapat menyelesaikan masalah dengan daftar yang ditautkan ganda atau pohon jika saya ingin menavigasi dan memodifikasi di tempat saya saat ini, tetapi tidak jelas apa yang harus dilakukan jika saya ingin fokus pada beberapa tempat secara bersamaan dan, misalnya, menukar dua elemen di dua tempat yang berjauhan. Bahkan lebih tidak jelas jika dapat digunakan dengan struktur "melingkar".
Alexey

2

Haskell tidak mencegah penggunaan struktur data yang bisa berubah. Mereka sangat kecil hati dan dibuat lebih sulit untuk digunakan karena fakta bahwa bagian-bagian kode yang menggunakannya akhirnya harus mengembalikan tindakan IO (yang akhirnya harus terikat dengan tindakan IO yang dikembalikan oleh fungsi utama), tetapi itu tidak membuatnya mustahil untuk menggunakan struktur seperti itu jika Anda benar-benar membutuhkannya.

Saya akan menyarankan menyelidiki penggunaan memori transaksional perangkat lunak sebagai jalan ke depan. Selain memberikan cara yang efisien untuk menerapkan struktur yang bisa berubah, ia juga memberikan jaminan yang sangat berguna untuk keselamatan benang. Lihat deskripsi modul di https://hackage.haskell.org/package/stm dan ikhtisar wiki di https://wiki.haskell.org/Software_transactional_memory .


Terima kasih, saya akan mencoba mempelajari tentang STM. Sepertinya ada metode yang lebih dalam Haskell memiliki berubah-ubah dan negara (aku sudah tersandung pada MVar, State, ST), jadi saya harus mencari tahu perbedaan mereka dan menggunakan dimaksudkan.
Alexey

@ Alexey: Poin bagus mengenai ST, IMO itu harus disebutkan dalam jawaban karena memungkinkan untuk menjalankan perhitungan stateful, kemudian membuang negara dan mengekstrak hasilnya sebagai nilai murni.
Giorgio

@Iorgio, mungkinkah menggunakan Haskell's STdengan STM untuk memiliki kondisi konkurensi dan sekali pakai?
Alexey

Hanya satu saran terminologi lagi: tindakan IO utama yang dikomposisikan tidak " dikembalikan oleh fungsi utama" tetapi ditugaskan ke mainvariabel. :) ( mainbahkan tidak memiliki fungsi.)
Alexey

Saya mengerti maksud Anda, tetapi masih "variabel" memiliki konotasi dalam benak kebanyakan orang sebagai nilai sederhana, daripada proses yang menghasilkan nilai, dan utama jelas lebih baik dianggap sebagai yang terakhir daripada yang sebelumnya. Perubahan yang Anda sarankan, meskipun secara teknis benar, memiliki potensi untuk membingungkan mereka yang tidak terbiasa dengan subjek.
Jules
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.