۱۵ - ۹نمونهی متفاوت، ارائهی یکسان
Monoid با بقیهی تایپکلاسها در هسکل از این لحاظ متفاوته که نوعدادههای زیادی با بیشتر از یک مانوید ِ معتبر وجود دارن. این رو در اعداد دیدیم، جمع و ضرب هردوشون مانویدهای درستی هستن، رفتارِ متفاوتی هم دارن. چنین مواقعی بهتره با newtype، این مانویدهای متفاوت رو از هم متمایز کنیم، مثلِ استفادهای که از Sum و Product کردیم.
جمع رو میشه یکی از عملیاتهای پیوستی ِ کلاسیک دونست، الحاق ِ لیستها هم همینطور. چنین چیزی رو برای ضرب هم شاید بشه گفت، چون همون الگو ِ "ترکیب ِ دو مقدارِ یک تایپ به یک مقدار" رو رعایت میکنه.
ولی برای بعضی نوعدادههای دیگه، مفهومِ پیوست وضوح کمتری داره. در این مواقع، عملیات ِ مانویدی بیشتر متمرکز به پیدا کردنِ یه جور مقدار خلاصه از مقادیرِ مجموعهست تا ترکیب اونها. بالاتر اشاره کردیم که مانویدها برای فولد کردن (یا بطور کلیتر کاتامورفیسمها) حائزِ اهمیتاند. شاید بهترین نگرش به mappend کردن، دیدنِ اون به چشمِ راهی برای متراکم کردنِ هر مجموعهای از مقادیر به یک مقدار خلاصه باشه تا راهی برای ترکیب ِ مقادیر. با نگاه به نمونههای Monoid برای Bool شروع میکنیم تا منظورمون رو بهتر نشون بدیم.
مقادیرِ بولیَن دو مانوید ِ ممکن دارن – یک مانوید برای عطف و یک مانوید برای فصل ِ منطقی. مثل اعداد، اینجا هم با newtype این دو نمونه رو از هم تمیز میدیم. برای Bool این newtypeها All و Any هستن:
Prelude> import Data.Monoid
Prelude> All True <> All True
All {getAll = True}
Prelude> All True <> All False
All {getAll = False}
Prelude> Any True <> Any False
Any {getAny = True}
Prelude> Any False <> Any False
Any {getAny = False}All عطف ِ منطقی رو نشون میده: اگر و فقط اگر همهی مقادیری که پیوست میده True باشن، جواب True میشه. Any مانوید ِ فصل ِ منطقیه: اگه یکی از مقادیر True باشه، True برمیگردونه. نگاه کردن اینها به چشم ترکیب یا mappend کردن یه جورایی عجیبه، مگر اینکه به یاد داشته باشیم mappend کردن بیشتر معنی متراکم کردن یا کاهیدن رو میده تا ترکیب کردن.
تایپ Maybe بیشتر از دو Monoid ِ ممکن داره. همهشون رو به ترتیب میبینیم، اما اون دوتایی که واضحتر از بقیهاند، First و Last هستن. مثلِ فصل ِ منطقی میمونن، اما صراحتاً اولویتِ چپترین یا راستترین موردِ موفق در یک سری از مقادیرِ Maybe رو بیان میکنن. با Bool فقط True یا False داریم – فرقی نداره مقادیرِ True یا False کجا باشن. اما با Maybe، در صورتِ موفق بودنِ چند مورد از مقادیر (Nothing نبودن) باید تصمیم بگیریم که کدوم مقدارِ Just رو انتخاب کنیم. First (به معنای اولین) و Last (به معنای آخرین) در واقع دو تصمیمِِ متفاوتاند.
First اولین یا چپترین مقدارِ غیرِ Nothing رو برمیگردونه:
Prelude> First (Just 1) `mappend` First (Just 2)
First {getFirst = Just 1}Last آخرین یا راستترین مقدارِ غیرِ Nothing رو برمیگردونه:
Prelude> Last (Just 1) `mappend` Last (Just 2)
Last {getLast = Just 2}حتی اگه یکی از مقادیر هم Nothing باشه، تا وقتی حداقل یک Just وجود داشته باشه، هردوشون بالاخره یه چیزی برمیگردونن:
Prelude> Last Nothing `mappend` Last (Just 2)
Last {getLast = Just 2}
Prelude> First Nothing `mappend` First (Just 2)
First {getFirst = Just 2}واضحه که اگه همهی مقادیر Nothing باشن، هردوی اینها هم Nothing برمیگردونن:
Prelude> First Nothing `mappend` First Nothing
First {getFirst = Nothing}
Prelude> Last Nothing `mappend` Last Nothing
Last {getLast = Nothing}همهی مثالهای بالا از newtype استفاده کردن تا یکتا بودنِ جفت تایپ و تایپکلاس رو رعایت کنن. مثل کاری که Sum و Product کردن.
حالا به حالت سوم برای Maybe Monoid نگاه کنیم.