۲۸ - ۲بیراهههایی که توضیحاتِ IO میرَن
خیلی از توضیحاتِ IO
غلطانداز یا سردرگماند. چندتا مثال از اون توضیحها رو دیدیم. بعضیها هم بهش میگن "IO Monad
" و ظاهراً IO
رو با Monad
یکی میدونن. درسته که IO
تایپیه که یه نمونه ِ Monad
داره، ولی فقط یه Monad
نیست و موندها هم فقط IO
نیستن. بعضی دیگه از توضیحها طوری القا میکنن که با ورود به IO
دیگه خلوص و شفافیتِ مرجع نابود میشن. بعضیها هم اصلاً چیزی از IO
نمیگن چون در حقیقت، با مبهم موندنِ IO
هم میشه خیلی از کارها رو انجام داد.
میخوایم چندتا راهنمایی برای سنجشِ منتقدانهی توضیحاتِ IO
بگیم. اول بریم سراغ یکی از شناختهشدهترین توضیحاتی که برای IO
داده شده. این توضیح سعی کرده IO
رو براساس State
توضیح بده.
State
رو آتیش بزن!
استفاده از State
برای فهموندنِ IO
خیلی وسوسهبرانگیزه. یه نگاه به این جمله که از اوایلِ مستندات ِ GHC.IO
گرفته شده بندازین:
IO Monad
فقط یه نمونه از موند ِ ST
ِه، که حالت ِش دنیای واقعی ِه.
وقتی تایپهای پشتپرده رو نگاه کنین، دلیلِ چنین توضیحاتی رو راحت میشه فهمید:
-- ghc-prim از
import GHC.Prim
import GHC.Types
newtype State s a
= State {runState :: s -> (a, s)}
-- :info IO
newtype IO a =
IO (State# RealWorld
-> (# State# RealWorld, a #))
قبوله، واقعاً شبیهِ State
ِه! با همهی اینها، اون قدری که اول به نظر میرسه فایده نداره.
مشکلِ این توضیح اینه که در واقع اون State#
* ِ پشتپردهی IO
، نه دیده میشه نه میشه باهاش تعامل داشت. State#
، به اون مفهومی که از State
، StateT
، یا حتی ST
استفاده میشه، ”State
“ نیست، ولی مطمئناً اینجا رفتارِ s
خیلی شبیهِ رفتارِ ST
ِه.
علامتِ #
نشون دهندهی یه تایپِ بَدوی ِه. این تایپها رو توی خودِ هسکل نمیشه تعریف کرد و از ماژول ِ GHC.Prim
صادر میشن.
اینجا نقشِ State
اینه که ترتیبِ اجراییههای IO
رو به GHC بگه، و مشخص کنه چه اجراییه ِ IO
یی یکتاست. اگه باز هم به مستندات ِ GHC.Prim
نگاه کنیم:
State#
تایپِ بَدَوی و لیفتنشده ِ حالتهاست. یک پارامترِ تایپی داره، پس میتونه State# RealWorld
یا State# s
باشه، که s
متغیر تایپی ِه. تنها نقشِ پارامترِ تایپی اینه که ریسههای حالتِ مختلف رو از هم سوا نگه داره. با هیچ چیزی ارائه نمیشه.
RealWorld
عمیقاً جادوییه. بَدِوی ِه، اما لیفتنشده نیست (در نتیجه ptrArg
). هیچ وقت با مقادیرِ تایپِ RealWorld
کار نمیکنیم؛ فقط در تایپ سیستم برای پارامتردار کردنِ State#
به کار میره.
وقتی میگن RealWorld
"با هیچ چیزی ارائه نمیشه،" منظورشون اینه که واقعاً صفر بیت حافظه مصرف میکنه. نشانههای حالت که در زیرِ تایپِ IO
هستن در زمانِ کامپایل پاک میشن و هیچ سرباری ای به زمانِ اجرا اضافه نمیکنن. پس در واقع مشکلِ توضیح دادنِ IO
براساسِ State
این نیست که غلطه؛ مشکل اینجاست که State
ای نیست که بشه تعاملِ مفهومداری، مشابهِ بقیهی تایپهای State
باهاش داشت.