۱۱ - ۶تایپ چیه و داده چیه؟

همونطور که گفتیم، تایپ‌ها ایستا اند و در لحظه‌ی کامپایل بررسی و مشخص میشن. قبل از زمان اجرا، تایپ‌ها معلوم‌اند، چه از طریق تعریفِ صریح، چه از طریقِ استنتاج تایپ، و همین مسئله اونها رو ایستا می‌کنه. داده‌ها چیزهایی‌اند که در زمان اجرا باهاشون کار داریم.

منظور از لحظه‌ی کامپایل دقیقاً زمانی‌ه که برنامه توسط GHC کامپایل، یا قبل از اجرا در یه REPL (مثل GHCi) چک میشه. زمان اجرا هم همون اجرا شدن ِ برنامه‌ست. تایپ‌ها مقادیر رو در خودشون پوشش میدن، و از همین راه میگن که چه مقداری از کدوم بخش از برنامه عبور می‌کنه.

ها type constructor نوع‌سازها یا   --  compile time زمان کامپایل یا

-------------------------------------  تفکیک دو مرحله

ها data constructor داده‌سازها یا  --  runtime زمان اجرا یا

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

با نوع‌داده ِ ‏‎Price‎‏ شروع می‌کنیم که یک نوع‌ساز، یک داده‌ساز، و یک آرگومانِ تایپی در داده‌ساز داره:

data Price =
--      (a)
  Price Integer deriving (Eq, Show)
-- (b)    [1]

‏‎(a)‎‏ نوع‌ساز ِه. و ‏‎(b)‎‏ یه داده‌ساز ِه که یک آرگومانِ تایپی (یعنی ‏‎[1]‎‏) می‌گیره.

مقدارِ ‏‎Price‎‏ تماماً به تعریفِ تایپ وابسته نیست؛ به تایپِ ‏‎Integer‎‏ هم وابستگی داره. اگه به هر دلیلی، ‏‎Integer‎‏ در گستره نباشه، مقادیرِ ‏‎Price‎‏ هم نمی‌تونیم ایجاد کنیم.

در مثال بعد دو تا تایپِ جمع، ‏‎Manufacturer‎‏ و ‏‎Airline‎‏، که هر کدوم سه داده‌ساز دارن تعریف می‌کنیم. توی این تایپ‌ها، هر داده‌ساز یکی از مقادیرِ ممکن برای تایپِ‌شون به حساب میان. هیچ کدوم آرگومانی نمی‌گیرن و در نتیجه بیشتر شبیهِ مقدار ثابت هستن تا سازنده، و همچنین همه‌شون در تعریفِ نوع‌داده ایجاد میشن.

data Manufacturer =
--       (c)
               Mini
--             (d)
             | Mazda
--             (e)
             | Tata
--             (f)
               deriving (Eq, Show)

‏‎(c)‎‏ نوع‌ساز برای ‏‎Manufacturer‎‏، و ‏‎(d)‎‏، ‏‎(e)‎‏، و ‏‎(f)‎‏ سه داده‌سازهاش هستن.

data Airline =
--     (g)
         PapuAir
--         (h)
       | CatapultsR'Us
--         (i)
       | TakeYourChancesUnited
--         (j)
         deriving (Eq, Show)

‏‎(g)‎‏ نوع‌ساز ِ ‏‎Airline‎‏ ِه، و سه داده‌ساز ِ ‏‎(h)‎‏، ‏‎(i)‎‏، و ‏‎(j)‎‏ داره.

حالا یه تایپ جمع که داده‌سازهاش آرگومان می‌گیرن رو ببینیم. تایپِ ‏‎Vehicle‎‏ متشکل از داده‌سازهای ‏‎Car‎‏ و ‏‎Plane‎‏ ِه، پس یه ‏‎Vehicle‎‏ یا یه ‏‎Car‎‏ ِه، یا یه ‏‎Plane‎‏. مثلِ ‏‎Price‎‏ که تایپِ ‏‎Integer‎‏ رو به عنوانِ آرگومان می‌گرفت، ‏‎Car‎‏ و ‏‎Plane‎‏ هم آرگومان‌هایی می‌گیرن:

data Vehicle = Car Manufacturer Price
--    (k)      (l)     [2]       [3]
             | Plane Airline 
--              (m)    [4]
             deriving (Eq, Show)

‏‎(k)‎‏ اینجا نوع‌ساز ِه؛ دو تا داده‌ساز هم داره، ‏‎(l)‎‏ و ‏‎(m)‎‏. آرگومان‌های تایپی با ‏‎[2]‎‏، ‏‎[3]‎‏، و ‏‎[4]‎‏ مشخص شدن. ‏‎[2]‎‏ و ‏‎[3]‎‏ آرگومان‌های تایپیِ داده‌ساز ِ ‏‎Car‎‏ اند، و ‏‎[4]‎‏ آرگومان تایپیِ داده‌ساز ِ ‏‎Plane‎‏. پس برای ساخت یه مقدارِ ‏‎Plane‎‏، یه مقدار از تایپِ ‏‎Airline‎‏ لازم داریم.

همه‌ی سازنده‌هایی که با حروفِ انگلیسی علامت‌گذاری کردیم، توسطِ نوع‌داده‌ها ایجاد میشن. آرگومان‌های تایپی که با اعداد نشون دادیم، قبل از تعریف‌ها وجود داشتن؛ تعاریفِ اونها خارج از این تعاریف وجود داره، و برای اینکه بتونیم در بخشی از این تعریف ازشون استفاده کنیم، باید در گستره باشن.

عبارتِ ‏‎deriving‎‏ رو قبلاً هم دیده بودیم. در همه‌ی نوع‌داده‌های بالا، مثل اکثر مواقع در کُدِ واقعی، نمونه ای از ‏‎Show‎‏ رو مشتق گرفتیم. این نمونه امکان چاپِ داده به عنوانِ نوشته روی صفحه رو میده. مشتق گرفتن ِ ‏‎Eq‎‏ هم رایجه، این کار عملگرهای تساوی رو برای اکثر نوع‌داده‌هایی که تساوی براشون معنی میده، خودبه‌خود مشتق می‌گیره. تایپکلاس‌های دیگه‌ای هم هستن که امکانِ مشتق‌گیری ِ نمونه‌هاشون باشه، این کار نیاز به نوشتنِ نمونه‌ها برای هر نوع‌داده و تایپکلاس به صورت دستی رو حذف می‌کنه (یادآوری: یه مثال از این رو در فصل تایپکلاس‌ها دیدین).

همونطور که دیدیم، داده‌سازها ممکنه آرگومان بگیرن، که این آرگومان‌ها تایپ‌های مشخصی‌اند، اما مقادیرِ مشخصی نیستن. در هسکلِ استاندارد، نمی‌تونیم مقادیرِ مشخص از تایپ‌ها رو، به عنوان آرگومانِ تایپی انتخاب کنیم. برای مثال نمیشه بگیم "‏‎Bool‎‏ بدونِ مقدارِ ‏‎False‎‏." اگه یه تابع، یا یه تعریفِ داده ‏‎Bool‎‏ می‌گیره، باید همه‌ی ‏‎Bool‎‏ رو قبول کنه.

تمرین‌ها: وسایل نقلیه

برای این تمرین از نوع‌داده‌هایی که بالاتر تعریف کردیم استفاده می‌کنیم. اگه تا الان اونها رو تو یه فایل نوشتین، می‌تونین ادامه بدین، اما اگه ننوشتین، لطفاً الان بنویسین. بعد هم چندتا داده ِ نمونه تعریف کنین، یا از اینها برای شروع استفاده کنین:

myCar    = Car Mini (Price 14000)
urCar    = Car Mazda (Price 20000)
clownCar = Car Tata (Price 7000)
doge     = Plane PapuAir

۱.

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

۲.

از روی تایپ سیگنچرهای زیر، توابع‌شون رو تعریف کنین:

isCar :: Vehicle -> Bool
isCar = undefined
-- .هست یا نه Car م. برای تشخیص اینکه

isPlane :: Vehicle -> Bool
isPlane = undefined

areCars :: [Vehicle] -> [Bool]
areCars = undefined

۳.

یه تابع بنویسین که تولیدکننده ِ یه داده رو بگه:

getManu :: Vehicle -> Manufacturer
getManu = undefined

۴.

حالا که ‏‎Manufacturer‎‏ برمی‌گردونه، اگه بهش یه داده ِ ‏‎Plane‎‏ بدیم چی میشه؟

۵.

خیلی خوب. فرض کنیم قرار شده اندازه ِ هواپیما رو هم به عنوانِ آرگومان به داده‌ساز ِ ‏‎Plane‎‏ اضافه کنین. این آرگومان رو که اضافه کردین، هرجا لازمه تغییرات مرتبط هم اعمال کنین.