مسیرها
/
Elm
Elm
/
تمرین‌ها
/
صندوق گنج
صندوق گنج

صندوق گنج

تمرین یادگیری

مقدمه

جنریک

مقدمه

«جنریک» یک ویژگی زبانی است که امکان استفاده‌ی دوباره از کد را فراهم می‌کند. برای مثال، نباید مهم باشد که یک لیست چه نوعی را در خود نگه می‌دارد تا بتوان طول آن را محاسبه کرد. به همین دلیل است که تابع length در امضای نوع خود از یک پارامتر نوع جنریک به اسم a استفاده می‌کند.

length : List a -> Int

پارامترها در نوع‌ها

وقتی یک نوع نسبت به نوع دیگری جنریک است، برای آن نوع دیگر از یک اسم با حروف کوچک استفاده می‌کنیم و آن را «پارامتر نوع» می‌نامیم. مثال‌های رایج، نوع‌های سفارشی List، Maybe و Result هستند.

-- Maybe is generic over the type a
type Maybe a
    = Nothing
    | Just a

someString : Maybe String
someString = Just "hello"

someInt : Maybe Int
someInt = Just 42

یک نکته‌ی مهم درباره‌ی اسم پارامترهای نوع این است که می‌توانند بیش از یک کاراکتر داشته باشند. تنها محدودیت این است که باید اسم‌هایی با حروف کوچک باشند. به همین دلیل، هر جا مفید باشد، تمایل داریم اسم‌هایی توصیفی برایشان انتخاب کنیم.

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

-- Result is generic over the types error and value
type Result error value
    = Ok value
    | Err error

نام‌های مستعار نوع رکورد هم می‌توانند پارامتر نوع داشته باشند، هرچند این کار کمتر رایج است.

-- Event is generic over the type a
type alias Event a =
    { at : Time
    , data : a 
    }

پارامترهای نوع در توابع

از آنجا که نوع‌ها می‌توانند جنریک باشند، توابع هم می‌توانند جنریک باشند. می‌توان توابعی نوشت که با نوع‌های جنریک کار می‌کنند، مانند Maybe.withDefault.

withDefault : a -> Maybe a -> a
withDefault default maybe =
    case maybe of
      Just value -> value
      Nothing -> default

توابعی که توابع دیگر را به عنوان پارامتر می‌گیرند، توابع مرتبه‌بالا نامیده می‌شوند و این‌ها هم می‌توانند جنریک باشند.

map : (a -> b) -> Maybe a -> Maybe b
map function maybe =
  case maybe of
    Just value ->
      Just (function value)

    Nothing ->
      Nothing

دستورالعمل‌ها

در این تمرین می‌خواهید یک TreasureChest «جنریک» (یا بهتر است بگوییم، جادویی!) بنویسید تا مقداری گنج را در آن نگهداری کنید.

1. نوع داده‌ی سفارشی جنریک TreasureChest را تعریف کنید

یک نوع داده‌ی سفارشی به نام TreasureChest تعریف کنید که تنها یک «گونه» دارد.

این گونه باید یک «مقدار همراه» از نوع String داشته باشد که برای نگهداری رمز عبور صندوق گنج به کار می‌رود.

همچنین این گونه باید یک مقدار همراه جنریک داشته باشد که برای نگهداری گنج به کار می‌رود.

این مقدار جنریک است تا گنج بتواند هرچه باشد.

2. تابع getTreasure را تعریف کنید

این تابع باید دو پارامتر بگیرد:

  • یک String (برای امتحان کردن رمز عبور)
  • یک نوع داده‌ی سفارشی جنریک TreasureChest

این تابع باید رمز عبور واردشده را با String موجود در TreasureChest بررسی کند.

این تابع باید یک Maybe برگرداند.

اگر رمزهای عبور مطابقت داشتند، Just را همراه با مقدار جنریک درون TreasureChest برگردانید (همان گنج!).

اگر رمزهای عبور مطابقت نداشتند، Nothing را برگردانید.

3. تابع multiplyTreasure را تعریف کنید

این تابع (مرتبه‌بالا) باید دو پارامتر بگیرد:

  • یک تابع ضرب‌کننده که یک پارامتر جنریک می‌گیرد و لیستی از همان نوع جنریک برمی‌گرداند
  • یک نوع داده‌ی سفارشی جنریک TreasureChest که آن هم همان نوع جنریک را دارد

این تابع باید تابع ضرب‌کننده را با گنج موجود در صندوق فراخوانی کند.

این تابع باید یک TreasureChest تازه برگرداند که همان رمز عبور اصلی را دارد و گنج ضرب‌شده (همان مقدار برگشتی) در آن قرار گرفته است.

ویرایش از طریق GitHub این لینک در پنجره یا زبانه‌ی جدیدی باز می‌شود
Elm Exercism

آماده‌اید صندوق گنج را شروع کنید؟

در Exercism ثبت‌نام کنید تا Elm را همراه با 28 مفهوم110 تمرین و مربی‌گری انسانی واقعی یاد بگیرید و در آن استاد شوید، همه‌ی این‌ها رایگان.