Ini adalah "interpretasi" yang disarankan dari IO
monad. Jika Anda ingin menganggap serius "interpretasi" ini, maka Anda harus menganggap serius "RealWorld". Tidak relevan apakah action world
akan dievaluasi secara spekulatif atau tidak, action
tidak memiliki efek samping, efeknya, jika ada, ditangani dengan mengembalikan keadaan alam semesta baru di mana efek-efek tersebut terjadi, misalnya paket jaringan telah dikirim. Namun, hasil dari fungsinya adalah ((),world)
dan oleh karena itu keadaan baru dari alam semesta adalah world
. Kami tidak menggunakan alam semesta baru yang mungkin telah kami evaluasi secara spekulatif di samping. Keadaan alam semesta adalah world
.
Anda mungkin mengalami kesulitan untuk menganggapnya serius. Ada banyak cara yang paling paradoksal dan tidak masuk akal. Konkurensi sangat tidak jelas atau gila dengan perspektif ini.
"Tunggu, tunggu," katamu. " RealWorld
Ini hanya 'token'. Ini sebenarnya bukan keadaan seluruh alam semesta." Oke, "interpretasi" ini tidak menjelaskan apa-apa. Namun demikian, sebagai detail implementasi , ini adalah model GHC IO
. 1 Namun, ini berarti bahwa kita memang memiliki "fungsi" ajaib yang sebenarnya memiliki efek samping dan model ini tidak memberikan panduan untuk artinya. Dan, karena fungsi-fungsi ini sebenarnya memiliki efek samping, kekhawatiran yang Anda ajukan benar-benar tepat sasaran. GHC tidak harus pergi keluar dari cara untuk memastikan RealWorld
dan fungsi-fungsi khusus tidak dioptimalkan dengan cara yang mengubah perilaku dimaksudkan program.
Secara pribadi (seperti yang mungkin terbukti sekarang), saya pikir model "melintas dunia" IO
ini tidak berguna dan membingungkan sebagai alat pedagogis. (Apakah ini berguna untuk implementasi, saya tidak tahu. Untuk GHC, saya pikir ini lebih merupakan artefak sejarah.)
Salah satu pendekatan alternatif adalah dengan melihat IO
sebagai menggambarkan permintaan dengan penangan respons. Ada beberapa cara untuk melakukan ini. Mungkin yang paling mudah diakses adalah menggunakan konstruksi monad gratis, khususnya yang bisa kita gunakan:
data IO a = Return a | Request OSRequest (OSResponse -> IO a)
Ada banyak cara untuk membuat ini lebih canggih dan memiliki sifat yang agak lebih baik, tetapi ini sudah merupakan perbaikan. Itu tidak membutuhkan asumsi filosofis yang mendalam tentang sifat realitas untuk memahami. Semua itu menyatakan bahwa itu IO
adalah salah satu program sepele Return
yang tidak melakukan apa-apa selain mengembalikan nilai, atau itu permintaan ke sistem operasi dengan penangan untuk tanggapan. OSRequest
dapat berupa sesuatu seperti:
data OSRequest = OpenFile FilePath | PutStr String | ...
Demikian pula, OSResponse
mungkin sesuatu seperti:
data OSResponse = Errno Int | OpenSucceeded Handle | ...
(Salah satu perbaikan yang dapat dilakukan adalah membuat hal-hal yang lebih ketik aman sehingga Anda tahu Anda tidak akan mendapatkan OpenSucceeded
dari PutStr
permintaan.) Model ini IO
menggambarkan permintaan yang ditafsirkan oleh beberapa sistem (untuk IO
monad "nyata" ini adalah runtuhnya Haskell itu sendiri), dan kemudian, mungkin, sistem itu akan memanggil penangan yang telah kami berikan tanggapan. Ini, tentu saja, juga tidak memberikan indikasi bagaimana permintaan seperti PutStr "hello world"
harus ditangani, tetapi juga tidak berpura-pura. Itu membuat eksplisit bahwa ini sedang didelegasikan ke beberapa sistem lain. Model ini juga cukup akurat. Semua program pengguna di OS modern perlu membuat permintaan ke OS untuk melakukan apa saja.
Model ini memberikan intuisi yang tepat. Sebagai contoh, banyak pemula melihat hal-hal seperti <-
operator sebagai "membuka" IO
, atau memiliki (sayangnya diperkuat) pandangan bahwa IO String
, katakanlah, adalah "wadah" yang "berisi" String
(dan kemudian <-
mengeluarkannya). Pandangan permintaan tanggapan ini membuat perspektif ini jelas salah. Tidak ada pegangan file di dalamnya OpenFile "foo" (\r -> ...)
. Sebuah analogi umum untuk menekankan ini adalah bahwa tidak ada kue di dalam resep untuk kue (atau mungkin "faktur" akan lebih baik dalam hal ini).
Model ini juga mudah digunakan dengan konkurensi. Kita dapat dengan mudah memiliki konstruktor untuk OSRequest
like Fork :: (OSResponse -> IO ()) -> OSRequest
dan kemudian runtime dapat menginterleave permintaan yang dihasilkan oleh penangan tambahan ini dengan penangan normal seperti yang diinginkannya. Dengan kepintaran Anda dapat menggunakan ini (atau teknik terkait) untuk benar-benar memodelkan hal-hal seperti konkurensi lebih langsung daripada hanya mengatakan "kami membuat permintaan ke OS dan hal-hal terjadi." Beginilah cara kerja IOSpec
perpustakaan .
1 Pelukan menggunakan implementasi berbasis kelanjutan IO
yang kira-kira mirip dengan apa yang saya jelaskan meskipun dengan fungsi buram bukan tipe data eksplisit. HBC juga menggunakan implementasi berbasis kelanjutan yang dilapisi IO berbasis aliran respons-permintaan lama. NHC (dan dengan demikian YHC) menggunakan thunks, yaitu kira-kira IO a = () -> a
meskipun ()
disebut World
, tetapi tidak melakukan state-passing. JHC dan UHC pada dasarnya menggunakan pendekatan yang sama dengan GHC.