۴ - ۳آناتومی تعریف داده

تعریفِ داده راهی برای تعریفِ تایپ‌هاست.

نوع‌ساز، اسمِ تایپ‌ه و با حروفِ بزرگ شروع میشه. وقتی تایپ سیگنچرها رو می‌خونین یا می‌نویسین (در سطحِ نوعی ِ کُد هستین)، از اسمِ تایپ‌ها، یا نوع‌سازها استفاده می‌کنین.

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

برای آشنایی، و اینکه چطور نوع‌داده‌‌ها درست میشن، با یه تایپِ پایه مثل ‏‎Bool‎‏ شروع می‌کنیم. تایپِ ‏‎Bool‎‏، که به نامِ ریاضیدانِ بزرگ، جورج بول و سیستمِ منطق او نامگذاری شده، مقادیر واقعی رو تعریف می‌کنه. از اونجا که فقط دو مقدارِ واقعی وجود دارن، ‏‎Bool‎‏ هم فقط دو داده‌ساز داره:

-- Bool تعریفِ
data Bool = False | True
--    [1]    [2] [3] [4] 

۱.

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

۲.

داده‌ساز برای مقدار ‏‎False‎‏.

۳.

خط عمودی ‏‎|‎‏ که تعیین کننده‌ی نوعِ جمع یا فصل منطقی (یا) ِه.

۴.

داده‌ساز برای مقدارِ ‏‎True‎‏.

به کلِ اون عبارت میگیم تعریفِ داده. تعریف داده‌‌ها می‌تونن شکل‌های دیگه هم داشته باشن – بعضی تایپ‌ها عطفِ منطقی (و) دارن (برخلافِ این مثال که فصلِ منطقی ِه)، بعضی نوع‌سازها و داده‌سازها هم آرگومان دارن. با وجودِ این تفاوت‌ها، همه‌شون نقاطِ مشترکی هم دارن: یکی کلیدواژه ِ ‏‎data‎‏ در اولِ تعریف‌ِه که بعد از اون، نوع‌ساز (یا همون اسمِ تایپ) نوشته میشه، علامت مساوی که نشون میده این یه تعریف‌ه، و آخر هم داده‌سازها (یا اسم مقادیری که در سطحِ جمله‌ای ِ کُد قرار می‌گیرن) که بعد از مساوی نوشته میشن.

شما می‌تونین تعریف یک نوع‌داده ِ از پیش تعریف شده رو با دستورِ ‏‎:info‎‏ در GHCi ببینین:

Prelude> :info Bool
data Bool = False | True

حالا ببینیم بخشهای مختلفِ یه نوع‌داده در کجاهای کُد دیده میشن. اگه تایپِ تابعِ ‏‎not‎‏ رو استعلام کنیم، می‌بینیم که یه مقدارِ ‏‎Bool‎‏ می‌گیره و یه مقدار ‏‎Bool‎‏ ِ دیگه برمی‌گردونه. پس تایپ سیگنچر، به نوع‌ساز یا اسمِ تایپ اشاره می‌کنه:

Prelude> :t not
not :: Bool -> Bool

ولی موقعِ استفاده از این تابع، از داده‌سازها (یا خودِ مقادیر) استفاده می‌کنیم:

Prelude> not True
False

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

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

با نوع‌داده ِ زیر، سؤال‌های زیر رو جواب بدین:

data Mood = Blah | Woot deriving Show

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

۱.

نوع‌ساز، یا اسمِ این تایپ چیه؟

۲.

اگه تابعی ورودیش یه مقدارِ ‏‎Mood‎‏ باشه، از چه مقادیری میشه استفاده کرد؟

۳.

میخوایم یه تابعِ ‏‎changeMood‎‏ بنویسیم که خُلق ِ کریس رو فوراً عوض کنه*. باید کاری شبیهِ تابعِ ‏‎not‎‏ انجام بده: با یک مقدارِ ورودی، تنها ورودی دیگه‌ی همون تایپ رو برگردونه. ما این تایپ سیگنچر رو براش نوشتیم:

changeMood :: Mood -> Woot

مشکل‌ش چیه؟

۴.

حالا خودِ تابع رو می‌نویسیم. با یه خُلق ِ ورودی، خُلق ِ دیگه رو برمی‌گردونه. هر اشکالی هست برطرف و تابع رو تکمیل کنین:

changeMood Mood = Woot
changeMood    _ = Blah

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

۵.

همه‌ی چیزهایی که بالاتر نوشتین رو تو یه فایل هم بنویسین – نوع‌داده (به همراهِ اون ‏‎deriving Show‎‏تایپ سیگنچر ِ اصلاح شده، و تابع تکمیل شده. فایل رو در GHCi بارگذاری کنین تا از درست بودنِ همه چیز مطمئن بشین.

*

م. کریس اسمِ یکی از نویسنده‌های این کتابه. اسم انتخابی تابع هم به معنی ‏‎تغییرِ خلق‎‏ ِه.