۱۱ - ۶تایپ چیه و داده چیه؟
همونطور که گفتیم، تایپها ایستا اند و در لحظهی کامپایل بررسی و مشخص میشن. قبل از زمان اجرا، تایپها معلوماند، چه از طریق تعریفِ صریح، چه از طریقِ استنتاج تایپ، و همین مسئله اونها رو ایستا میکنه. دادهها چیزهاییاند که در زمان اجرا باهاشون کار داریم.
منظور از لحظهی کامپایل دقیقاً زمانیه که برنامه توسط 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
اضافه کنین. این آرگومان رو که اضافه کردین، هرجا لازمه تغییرات مرتبط هم اعمال کنین.