۱۱ - ۴نوعسازها و کایندها
یه بار دیگه نوعداده ِ لیست رو ببینیم:
data [] a = [] | a : [a]
قبل از اینکه یه لیست بده، باید اول به یه تایپِ معیّن اعمال بشه. اگه نشانِ گونه یا کایند سیگنچر ِ این رو ببینیم، یه جور توازی با توابع هم میبینیم.
کایندها، تایپِ تایپ هستن، یا یه سطح بالاتر از تایپ. کایندها در هسکل با *
نشون داده میشن. اگه تایپی با *
نشون داده بشه، مشخصه که یه تایپِ معیّن و تماماً اعمال شدهست. اما اگه کایندِش * -> *
باشه، اون تایپ هم مشابهِ یه تابع، منتظرِ اعمال شدنه.
این دو تا رو مقایسه کنین:
Prelude> let f = not True
Prelude> :t f
f :: Bool
Prelude> let f x = x > 3
Prelude> :t f
f :: (Ord a, Num a) => a -> Bool
f
ِ اول هیچ آرگومانی نمیگیره و برای تولیدِ یه مقدار، منتظرِ اعمال شدن به چیزی نیست، پس تایپ سیگنچر ِش یه تایپِ معیّن ِه – به نبودِ یه فِلشِ تابع دقت کنین. اما f
ِ دوم منتظرِ اعمال شدن به یه x
ِه، پس در تایپ سیگنچر ِش هم فِلِش وجود داره. همین که به یه مقدار اعمال بشه، تایپش هم معیّن میشه:
Prelude> let f x = x > 3
Prelude> :t f 5
f :: Bool
استعلام ِ کایندِ یه نوعساز (نه یه دادهساز) در GHCi با دستورِ :kind
یا :k
انجام میشه. کایند سیگنچرها اطلاعاتِ مشابهی دربارهی نوعسازها میدن:
Prelude> :k Bool
Bool :: *
Prelude> :k [Int]
[Int] :: *
Prelude> :k []
[] :: * -> *
هم Bool
و هم [Int]
تایپهای معیّن و تماماً اعمال شده هستن، و در نتیجه کایند سیگنِچر ِشون هم هیچ فِلِشی نداره. یعنی برای مشخص و معیّن شدن منتظرِ اعمال شدن به چیزی نیستن. اما کایندِ []
فرق داره، * -> *
: چون برای معیّن شدنِ خودش، باید به یه تایپِ معیّن اعمال بشه. این همون چیزیه که ساز در نوعساز بهش اشاره داره.