انواع داده جبری؛ پایهٔ طراحی نرمافزار
خلاصهٔ کاملتر
نویسندهٔ این مقاله میگه هیچ چیز به اندازهٔ algebraic data types (یا ADT، یعنی ساختن نوعهای جدید از ترکیب نوعهای دیگه) روی طرز طراحی نرمافزارش اثر نذاشته. اسمش آکادمیکه ولی ایدهش سادهست. product type مثل یه آبجکت معمولیه: یه User هم id داره و هم role. sum type میگه یه مقدار یا این حالته یا اون یکی: یه Session یا Anonymous هست یا Authenticated، و فقط تو حالت Authenticated یه User همراهش هست. به گفتهٔ نویسنده بیشتر فایدهها از همین sum type میاد.
اولین فایده اینه که قوانین دامنه بهجای کامنت و مستندات، تو خود تایپ نوشته بشن. مثال مقاله تنظیمات رنگ یه سایته: سایت یا بین حالت روشن و تاریک جابهجا میشه یا یه حالت ثابت داره. اگه اینو با یه boolean و چند تا فیلد nullable مدل کنی، کلی ترکیب بیمعنی مجاز میشه. ولی با یه sum type با دو حالت Switchable و Fixed، هر حالت دقیقاً فیلدهای خودشو داره. به این میگن «make invalid states unrepresentable»، یعنی حالت نامعتبر اصلاً نتونه ساخته بشه.
فایدهٔ دوم اینه که خطا بخشی از قرارداد تابع بشه. تو زبانهای مبتنی بر exception، امضای parsePort فقط میگه یه عدد برمیگردونه. Rust برای خطاهای قابلانتظار از Result استفاده میکنه که یا مقدار موفق T رو داره یا خطای E. خود خطا هم میتونه sum type باشه، مثل NotANumber و OutOfRange که دومی حداقل و حداکثر مجاز رو همراهش داره. نویسنده میگه چون کل اکوسیستم Rust همین قراردادو رعایت میکنه، caller بدون رسیدگی به خطا به مقدار نمیرسه.
نبودِ مقدار هم باید تایپ خودشو داشته باشه. جاوااسکریپت هم null داره هم undefined و APIها ناهماهنگ ازشون استفاده میکنن. Rust بهجاش Option داره. اگه نبودِ کاربر یه نتیجهٔ عادی باشه ولی خود جستجو هم بتونه خراب بشه، میشه Option رو داخل Result گذاشت تا سه حالت روشن داشته باشیم: Ok(Some(user)) یعنی پیدا شد، Ok(None) یعنی وجود نداره و Err(error) یعنی جستجو شکست خورد.
بعد نوبت pattern matching با match میرسه. تو Rust یه match باید exhaustive باشه، یعنی همهٔ حالتها رو پوشش بده وگرنه کامپایل نمیشه. هر شاخه هم فقط به دادهٔ همون حالت دسترسی داره، پس null check یا type cast لازم نیست. موقع تغییر هم کمک میکنه: اگه نقش Staff به Role اضافه بشه، هر match روی Role، مثلاً تو عملیات بن کردن کاربر، دیگه کامپایل نمیشه. یعنی کامپایلر خودش لیست جاهایی که باید بازبینی بشن رو بهت میده.
نویسنده میگه وقتی چند ورودی، مثل مقصد و سرعت ارسال، روی نتیجه اثر دارن، میشه روی هر دو با هم match کرد. اونوقت کامپایلر چکلیست ترکیبها رو نگه میداره و تو فقط روی یه حالت تمرکز میکنی. به نظر اون sum type و exhaustive matching دیگه امکانات اضافه نیستن، بلکه حداقل چیزیه که باید از یه زبان برنامهنویسی انتظار داشت.
نکات کلیدی:
- دو نوع اصلی ADT وجود داره: product type (این و اون) و sum type (این یا اون)
- با sum type میشه قوانین دامنه رو تو تایپ نوشت تا حالت نامعتبر ساخته نشه
- Rust خطاهای قابلانتظار رو با Result و نبودِ مقدار رو با Option نشون میده، نه با exception و null
- match تو Rust باید همهٔ حالتها رو پوشش بده، وگرنه کد کامپایل نمیشه
- اضافه کردن یه حالت جدید به یه sum type، همهٔ matchهای قدیمی رو تبدیل به خطای کامپایل میکنه




