Це запропоноване «тлумачення» IOмонади. Якщо ви хочете сприймати цю "інтерпретацію" серйозно, тоді вам потрібно сприймати "RealWorld" серйозно. Незалежно від того, action worldотримано спекулятивну оцінку чи ні, actionне має жодних побічних ефектів, її ефекти, якщо такі є, обробляються шляхом повернення нового стану Всесвіту там, де ці ефекти виникли, наприклад, надісланий мережевий пакет. Однак результатом функції є ((),world)і тому новий стан Всесвіту є world. Ми не використовуємо новий всесвіт, який, можливо, ми спекулятивно оцінили на стороні. Стан Всесвіту є world.
Напевно, вам важко сприймати це серйозно. Є багато способів, як це в кращому випадку поверхово парадоксально і безглуздо. Конкурс є особливо неочевидним або божевільним у цій перспективі.
«Почекай, почекай», - кажеш ти. " RealWorldце просто" маркер ". Це насправді не стан усього Всесвіту". Гаразд, тоді ця "інтерпретація" нічого не пояснює. Тим не менш, як деталь реалізації , це, як моделі GHC IO. 1 Це означає, що у нас є магічні "функції", які насправді мають побічні ефекти, і ця модель не дає ніяких вказівок щодо їх значення. І оскільки ці функції насправді мають побічні ефекти, ви викликаєте занепокоєння повністю. GHC дійсно повинен вийти зі свого шляху , щоб переконатися , що RealWorldі ці спеціальні функції не оптимізовані таким чином , щоб змінити цільове поведінка програми.
Особисто (як це, мабуть, очевидно зараз), я вважаю, що ця "миротворча" модель IOпросто марна і заплутана як педагогічний інструмент. (Чи корисно це для впровадження, я не знаю. Для GHC, я думаю, це більше історичний артефакт.)
Один з альтернативних підходів - розглядати IOяк опис запитів з обробниками відповідей. Існує кілька способів зробити це. Напевно, найбільш доступним є використання безкоштовної конструкції монади, зокрема ми можемо використовувати:
data IO a = Return a | Request OSRequest (OSResponse -> IO a)
Існує багато способів зробити це більш досконалим і мати дещо кращі властивості, але це вже вдосконалення. Для розуміння цього не потрібно глибоких філософських припущень щодо природи реальності. Все, що він стверджує, - IOце або тривіальна програма, Returnяка не робить нічого, крім повернення значення, або це запит в операційну систему з обробником для відповіді. OSRequestможе бути щось на кшталт:
data OSRequest = OpenFile FilePath | PutStr String | ...
Так само OSResponseможе бути щось на кшталт:
data OSResponse = Errno Int | OpenSucceeded Handle | ...
(Одне з удосконалень , які можна зробити, щоб зробити речі більш тіпобезопасно так , що ви знаєте , що ви не отримаєте OpenSucceededвід PutStrзапиту.) Ці моделі , IOяк описують запитів , які інтерпретуються деякої система (для «реального» IOмонади це сам час виконання Haskell), а потім, можливо, ця система викличе обробник, який ми надали у відповідь. Це, звичайно, також не вказує на те, як PutStr "hello world"слід обробляти такий запит , але він також не претендує. Зрозуміло, що це делеговано іншій системі. Ця модель також досить точна. Усі користувацькі програми в сучасних ОС повинні робити запити в ОС, щоб зробити що-небудь.
Ця модель забезпечує правильні інтуїції. Наприклад, багато початківців розглядають такі речі, як <-оператор, як "розгортання" IOабо мають (на жаль, підкріплені) погляди, що IO String, скажімо, є "контейнером", який містить " Strings" (а потім <-витягує їх). Цей погляд-відповідь робить цю перспективу явно неправильною. Немає файлової обробки всередині OpenFile "foo" (\r -> ...). Поширена аналогія, яка наголошує на цьому, полягає в тому, що в рецепті торта немає торта (або, можливо, «фактура» була б кращою в цьому випадку).
Ця модель також легко працює з одночасністю. Ми можемо легко створити конструктор для OSRequestподібних, Fork :: (OSResponse -> IO ()) -> OSRequestі тоді час виконання може переплутати запити, які виробляє цей додатковий обробник, із звичайним обробником, як це не подобається. З деякою кмітливістю ви можете використовувати цю техніку (або пов'язані з нею методи), щоб насправді моделювати речі, такі як паралельність, безпосередньо, а не просто говорити "ми робимо запит в ОС і все відбувається" Так працює IOSpecбібліотека .
1 Hugs використовував реалізацію на основі продовження, IOяка приблизно схожа на те, що я описую, хоча і з непрозорими функціями замість явного типу даних. HBC також використовувала реалізацію, що базується на продовженні, шарується над старим IO на основі запиту-відповіді. NHC (і, таким чином, YHC) використовував громовідвід, тобто приблизно, IO a = () -> aхоча це ()називалося World, але це не робить державний прохід. JHC та UHC використовували в основному той самий підхід, що і GHC.