۱۶ - ۵قوانین فانکتور

نمونه‌های تایپکلاسِ ‏‎Functor‎‏ باید از دو قانون تبعیت کنن. درک این قوانین برای درکِ فانکتور و نوشتنِ نمونه‌های تایپکلاسیِ ترکیب‌پذیر و گویا خیلی مهمه.

همانی

اولین قانون، قانون ِ همانی ِه:

fmap id == id

اگه تابع همانی رو ‏‎fmap‎‏ کنیم، باید همون جوابی رو بده که نتیجه‌ی اعمال ِ خودِ تابعِ همانی به اون مقداره. با نگاشت ِ ‏‎id‎‏ نباید هیچ تغییری در ساختار ِ بیرونی (‏‎f‎‏) که داریم از روش نگاشت می‌کنیم پیش بیاد. به همین دلیل هم با ‏‎id‎‏ یکسان‌ه. اگه از نگاشت ِ تابعِ ‏‎a -> b‎‏ از روی یه ساختار، چیزِ جدیدی عایدمون نمیشه، هیچ چیز هم نباید تغییر کنه:

Prelude> fmap id "Hi Julie"
"Hi Julie"
Prelude> id "Hi Julie"
"Hi Julie"

می‌تونین با چندتا ساختار ِ دیگه هم امتحان کنین.

ترکیب‌پذیری

قانون ِ دوم برای فانکتور، قانونِ ترکیب‌پذیری ِه:

fmap (f . g) == fmap f . fmap g

این قانون مرتبط با ترکیب‌پذیری ِ ‏‎fmap‎‏ ِه. اگه دو تابعِ ‏‎f‎‏ و ‏‎g‎‏ رو با هم ترکیب کنیم، بعد اون رو از روی یه ساختار ‏‎fmap‎‏ کنیم، باید همون جوابی رو بده که اگه اول ‏‎fmap‎‏ ِشون می‌کردیم بعد ترکیب‌ِشون می‌کردیم:

Prelude> fmap ((+1) . (*2)) [1..5]
[3,5,7,9,11]
Prelude> fmap (+1) . fmap (*2) $ [1..5]
[3,5,7,9,11]

اگه تعریفِ یه ‏‎fmap‎‏ اینطور کار نمی‌کنه، فانکتور ِ درستی نیست.

حفظ ِ ساختار

هردوی این قانون‌ها به اون قانون ِ اساسی که ساختار باید دست‌نخورده باقی بمونه اشاره دارن.

تنها چیزی که اجازه داریم از ‏‎f‎‏ بدونیم، اینه که ‏‎Functor‎‏ داره:

fmap :: Functor f => (a -> b) -> f a -> f b

‏‎f‎‏ با تایپکلاسِ ‏‎Functor‎‏ محدود شده؛ از این تعریف، تنها چیزی که راجع بهش میدونیم همینه. همونطور که در پلی‌مورفیسم با محدودیت تایپکلاسی دیدیم، اینجا ‏‎f‎‏ می‌تونه هر تایپی که یه نمونه از ‏‎Functor‎‏ داره باشه. عملیات ِ اصلی که این تایپکلاس برای تایپ‌هاش تأمین می‌کنه، همین ‏‎fmap‎‏ ِه. به دلیلِ اینکه ‏‎f‎‏ در طولِ تایپِ ‏‎fmap‎‏ یکنواخت می‌مونه، هر تایپی که باشه میدونیم یک آرگومان می‌گیره ( مثل ‏‎f a‎‏ و ‏‎f b‎‏) و ساختار‌ایه که تابع رو از روش لیفت می‌کنیم تا به مقدارِ داخلی‌ش اعمال کنیم.