Ini sebagian besar pertanyaan teoretis tentang FP, tetapi saya akan mengambil petualangan teks (seperti Zork sekolah lama) untuk mengilustrasikan poin saya. Saya ingin tahu pendapat Anda tentang bagaimana Anda memodelkan simulasi stateful dengan FP.
Petualangan teks tampaknya benar-benar membutuhkan OOP. Sebagai contoh, semua "kamar" adalah contoh dari sebuah Room
kelas, Anda dapat memiliki Item
kelas dasar dan antarmuka seperti Item<Pickable>
untuk hal-hal yang dapat Anda bawa dan sebagainya.
Pemodelan dunia dalam FP bekerja secara berbeda, terutama jika Anda ingin menegakkan kekekalan di dunia yang harus bermutasi saat permainan berlangsung (objek dipindahkan, musuh dikalahkan, skor bertambah, pemain mengubah lokasinya). Saya membayangkan satu objek besar World
yang memiliki semuanya: kamar apa yang bisa Anda jelajahi, bagaimana mereka terhubung, apa yang dibawa pemain, tuas apa yang telah dipicu.
Saya pikir pendekatan murni pada dasarnya akan melewatkan objek besar ini ke fungsi apa pun dan mengembalikannya (mungkin dimodifikasi). Sebagai contoh, saya memiliki moveToRoom
fungsi yang mendapat World
dan mengembalikannya dengan World.player.location
diubah ke ruang baru, World.rooms[new_room].visited = True
dan seterusnya.
Bahkan jika ini adalah cara yang lebih "benar", tampaknya ini menegakkan kemurnian demi hal itu. Bergantung pada bahasa pemrogramannya, melewatkan objek yang berpotensi sangat besar ini World
bolak-balik mungkin mahal. Juga, setiap fungsi mungkin perlu memiliki akses ke World
objek apa pun . Sebagai contoh, sebuah ruangan mungkin dapat diakses atau tidak tergantung pada tuas yang dipicu di ruangan lain karena itu mungkin banjir, tetapi jika pemain membawa jaket pelampung, itu tetap bisa masuk. Monster mungkin agresif atau tidak, tergantung pada apakah pemain telah membunuh sepupunya di ruangan lain. Ini berarti bahwa roomCanBeEntered
fungsi perlu mengakses World.player.invetory
dan World.rooms
, describeMonster
perlu mengakses World.monsters
dan sebagainya (pada dasarnya, Anda haruslulus seluruh beban sekitar). Bagi saya ini benar-benar memanggil untuk variabel global, bahkan jika ini semua kecuali gaya pemrograman yang baik terutama dalam FP.
Bagaimana Anda memecahkan masalah ini?
sumber
Jawaban:
Ingatlah bahwa bahasa fungsional menggunakan struktur data dan fungsi yang dipisahkan alih-alih objek. Misalnya, Anda akan memiliki satu set kamar dan daftar barang inventaris sebagai dunia sebagai gantinya.
Idealnya, Anda juga akan membatasi jumlah data yang Anda berikan pada fungsi hingga berapa banyak yang sebenarnya mereka butuhkan sebanyak mungkin alih-alih melewati seluruh dunia (katakanlah Anda mengekstrak satu kamar yang relevan dari dunia Anda; tentu saja dunia yang saling bergantung secara penuh bisa sulit untuk dilakukan. terpisah). Hasilnya akan dimasukkan kembali ke dalam struktur data dunia, menciptakan keadaan baru. Anda tidak dapat memodelkan status tanpa menggunakan status; seperti yang Anda katakan beberapa hal secara inheren membutuhkan mutasi.
Sebagian besar bahasa fungsional praktis menyediakan cara untuk mewujudkan mutasi baik secara langsung (misalnya, monad ST di Haskell atau transien di Clojure), atau mensimulasikannya secara efisien (sering kali dengan menggunakan kembali bagian struktur data yang tidak berubah (struktur data default Clojure adalah contoh yang baik di sini) ). Bagaimanapun kemurnian dipertahankan.
Karena jumlah status yang perlu dimutasi tampaknya terbatas, saya tidak akan terlalu khawatir tentang masalah kinerja dan mengikuti pendekatan fungsional yang naif (mungkin sudah dioptimalkan).
Pilihan berbeda yang saya lihat adalah mengembalikan hanya instruksi untuk mengubah beberapa bagian dunia dari fungsi individual Anda, dan kemudian memperbarui dunia Anda sesuai dengan ini. Serangkaian posting blog yang menjelaskan hal ini tersedia di http://prog21.dadgum.com/23.html .
Kedua jawaban ini lebih berurusan dengan bagaimana mengatur perubahan daripada tidak menyerahkan seluruh dunia Anda ke fungsi, karena yang saling bergantung sempurna tidak dapat dibagi berdasarkan definisi - tetapi cobalah dan lakukan sebaik mungkin dalam kasus Anda, yang tidak hanya fungsional, tetapi juga praktik yang baik.
sumber
Saya sendiri, saya pasti akan melihat kemampuan bahasa yang dimaksud untuk mengakses beberapa bentuk database. Sebagian besar peristiwa yang terjadi untuk mengubah keadaan dunia secara bersamaan hanya akan direkam ke disk, dan tidak akan mempengaruhi pemain saat ini di dalam ruangan saat ini (di luar keadaan khusus seperti ledakan, atau dalam MMO, saklar yang membuka pintu dari jarak jauh, teriakan pemain lain, dll).
Dengan demikian, klien saat ini benar-benar hanya perlu menyadari
Room
objek, dan hal-hal yang mempengaruhinya secara langsung.noticableEventsOutsideRoom
maka bisa saja menjadi subkelas yangRoom
terpengaruh oleh perubahan terbaru ke database, dan objek game Anda menjadi jauh lebih kecil.sumber
update mobs set agro=1 where distance<5
dan menjadi selesai dengan itu. Mungkin itu bukan praktik terbaik, tetapi itu sesuai dengan tujuan saya. Adapun pathfinding melalui database, kita selalu bisa menggunakan algoritma jalur terpendek Dijkstra ...Solusi sebenarnya bukan dengan mengumpulkan semuanya ke objek Dunia yang besar, lalu menyebarkannya. Sebagai gantinya, Anda disarankan untuk secara akurat menentukan jenis fungsi yang Anda hadapi. Inilah beberapa contoh:
Contoh buruknya adalah mencoba untuk memodifikasi objek yang ada, tetapi contoh yang baik adalah mencoba untuk menciptakan dunia dari ruang keadaan yang dimiliki permainan Anda. Pada dasarnya, untuk menciptakan dunia, Anda perlu mengetahui semua data yang diperlukan untuk memilih dunia yang benar.
sumber