۱۱ - ۵داده‌سازها و مقادیر

کمی قبل‌تر گفتیم که گزارش هسکل ثابت‌های تایپ و نوع‌سازها رو از هم متمایز میدونه. یه تفاوتِ مشابه بین داده‌سازها و مقادیرِ ثابت هم میشه دید.

data PugType = PugData
--   [1]         [2]

data HuskyType a = HuskyData
--       [3]          [4] 

data DogueDeBordeaux doge = DogueDeBordeaux doge
--        [5]                     [6]

۱.

‏‎PugType‎‏ یه نوع‌ساز ِه که هیچ آرگومانی نمی‌گیره، پس میشه گفت یه ثابت تایپ ِه (همونطور که در گزارش هسکل اومده). این تایپ فقط یک سازنده رو می‌شماره.

۲.

‏‎PugData‎‏ تنها داده‌ساز برای تایپِ ‏‎PugType‎‏ ِه. اتفاقاً هم یه مقدارِ ثابت ِه (هیچ آرگومانی نمی‌گیره). هر وقت تابعی ببینیم که یه مقدار با تایپِ ‏‎PugType‎‏ لازم داره، میدونیم که اون مقدار حتماً ‏‎PugData‎‏ هست.

۳.

‏‎HuskyType‎‏ یه نوع‌ساز ِه، و یک متغیر تایپ با پلی‌مورفیسم ِ پارامتریک به عنوان آرگومان می‌گیره. یک داده‌ساز هم شمارش می‌کنه.

۴.

‏‎HuskyData‎‏ داده‌ساز برای ‏‎HuskyType‎‏ ِه. دقت کنین که متغیر تایپ ِ ‏‎a‎‏ به عنوانِ آرگومان برای ‏‎HuskyData‎‏ نیومده، و اصلاً هیچ‌جا بعد از ‏‎=‎‏ نوشته نشده. یعنی آرگومان تایپیِ ‏‎a‎‏ خیالی ِه؛ به عبارت دیگه "شاهد نداره." بعداً درباره‌ی این بیشتر صحبت می‌کنیم. ‏‎HuskyData‎‏ هم مثلِ ‏‎PugData‎‏ یه مقدارِ ثابت ِه.

۵.

‏‎DogueDeBordeaux‎‏ هم مشابهِ ‏‎HuskyType‎‏ یه نوع‌ساز با یک متغیرِ تایپی ِه، فقط اسم آرگومان‌ش بجای ‏‎a‎‏ شده ‏‎doge‎‏. چرا؟ چون اسم متغیرها اهمیتی ندارن. این تایپ هم فقط یک سازنده رو می‌شماره.

۶.

تنها داده‌ساز برای ‏‎DogueDeBordeaux‎‏. این داده‌ساز با خودِ نوع‌ساز هم‌اسم ِه، اما این دو تا یک چیز نیستن. متغیرِ تایپی ِ ‏‎doge‎‏ در نوع‌ساز، در داده‌ساز هم ظاهر شده؛ و چون این دو تا یه متغیر تایپ اند، پس باید با هم یکی باشن: ‏‎doge‎‏ برابرِ ‏‎doge‎‏. مثلاً اگه تایپ ‏‎DogueDeBordeux [Person]‎‏ هست، باید یه لیست از ‏‎Person‎‏ داخلِ مقدارِ ‏‎DogueDeBordeux‎‏ باشه. از اونجا که برای رسیدن به یه مقدارِ معیّن، ‏‎DogueDeBordeux‎‏ باید اول اعمال بشه، هر مقداری در زمان اجرا میشه باهاش ساخت.

تایپِ مقدار رو میشه استعلام کرد (تایپِ داده‌ساز، نه نوع‌ساز – اینطور وقتها که اسمِ نوع‌ساز و داده‌ساز یکیه، ممکنه گیج‌کننده باشه، اما این کار خیلی تو هسکل رایجه. کامپایلر مثل ما فانی‌ها اسم تایپ‌ها رو با اسم مقادیر قاطی نمی‌کنه):

Prelude> :t DogueDeBordeaux
DogueDeBordeaux :: doge
                -> DogueDeBordeaux doge

این تایپ سیگنچر میگه وقتی ‏‎doge‎‏ به یه تایپِ معیّن مقیّد میشه، بعدش یه مقدار با تایپِ ‏‎DogueDeBordeaux doge‎‏ میشه. یعنی این الان یه مقدار نیست، بلکه تعریفی از نحوه‌ی ساختِ مقداری از اون تایپ‌ه.

حالا از هرکدوم از این تایپ‌ها یه مقدار می‌سازیم:

myPug = PugData :: PugType

myHusky :: HuskyType a
myHusky = HuskyData

myOtherHusky :: Num a => HuskyType a
myOtherHusky = HuskyData

myOtherOtherHusky :: HuskyType [[[[Int]]]]
myOtherOtherHusky = HuskyData
-- برخلاف ظاهر، شاهدی نداره     ^

در مثال زیر، عدد ۱۰ با ‏‎Int‎‏ که متغیر تایپی بهش مقیّد شده همخونی داره، به همین خاطر هم تایپچک میشه:

myDoge :: DogueDeBordeaux Int
myDoge = DogueDeBordeaux 10

اما در این مثال، ۱۰ با انقیاد ِ متغیرِ تایپی به ‏‎String‎‏ جور نیست و کار نمی‌کنه:

badDoge :: DogueDeBordeaux String
badDoge = DogueDeBordeaux 10

تو این چندتا مثال دیدیم که با سازنده‌ها میشه مقادیرِ تایپ‌های مختلف رو ساخت و در تایپ سیگنچرها به تایپ‌ها اشاره کرد. یه توازی بین داده‌سازها و نوع‌سازها وجود داره که با یه نوع‌داده ِ دیگه نشون میدیم:

data Doggies a =
    Husky a
  | Mastiff a
  deriving (Eq, Show)

-- نوع‌سازی که منتظر یه آرگومان‌ه
Doggies

دقت کنین که کایند سیگنچر ِ نوع‌ساز، و تایپ سیگنچر ِ هر کدوم از داده‌سازهاش، همگی مشابهِ تابع می‌مونن.

این نوع‌ساز باید اعمال بشه تا یه تایپِ معیّن بده:

Prelude> :k Doggies
Doggies :: * -> *

و این داده‌ساز باید اعمال بشه تا یه مقدارِ معیّن بده:

Prelude> :k Husky
Husky :: a -> Doggies a

پس سازنده‌ها اگه هیچ آرگومانی نگیرن، مثل ثابت‌ها رفتار می‌کنن (ثابت ِ تایپی یا مقداری). اگر هم آرگومان بگیرن، مشابه توابعی (مقداری یا تایپی) رفتار می‌کنن که به غیر از اعمال شدن، کار دیگه‌ای انجام نمیدن.

تمرین‌ها: انواع سگ

با فرضِ نوع‌داده‌های تعریف شده در بخش بالا،

۱.

آیا ‏‎Doggies‎‏ یه نوع‌ساز ِه یا یه داده‌ساز؟

۲.

گونه یا کایندِ ‏‎Doggies‎‏ چیه؟

۳.

کایندِ ‏‎Doggies String‎‏ چیه؟

۴.

تایپِ ‏‎Husky 10‎‏ چیه؟

۵.

تایپِ ‏‎Husky (10 :: Integer)‎‏ چیه؟

۶.

تایپِ ‏‎Mastiff "Scooby Doo"‎‏ چیه؟

۷.

آیا ‏‎DogueDeBordeaux‎‏ یه نوع‌ساز ِه یا یه داده‌ساز؟

۸.

تایپِ ‏‎DogueDeBordeaux‎‏ چیه؟

۹.

تایپِ ‏‎DogueDeBordeaux "doggie!"‎‏ چیه؟