অপ্যাক টাইপ হলো Elm-এ এনক্যাপসুলেশনের একটি কৌশল।
কেউ কেউ এটাকে ইনফরমেশন হাইডিং বা ইমপ্লিমেন্টেশনের খুঁটিনাটি লুকিয়ে রাখা বলেও ডাকেন।
ভ্যালিডেশন প্রয়োগ করতেও এগুলো সাধারণত ব্যবহৃত হয়, Parse, dont validate প্যাটার্ন ব্যবহার করে।
উদাহরণস্বরূপ, আপনার একটি EmailAddress অপ্যাক টাইপ থাকতে পারে, যেটি শুধু বৈধ ইমেইল ধারণ করতে পারে (একটি String-এর বিপরীতে, যেটি যেকোনো কিছু ধারণ করতে পারে)।
কাস্টম টাইপ-এর এক বা একাধিক ভ্যারিয়েন্ট থাকে, আর কম্পাইলার স্বয়ংক্রিয়ভাবে প্রতিটি ভ্যারিয়েন্ট তৈরির একটি ফাংশন বানিয়ে দেয়, ভ্যারিয়েন্ট-এর নাম ব্যবহার করে। কাস্টম টাইপ তৈরির এটাই একমাত্র উপায়। কম্পাইলার এই ভ্যারিয়েন্টগুলোর জন্য ডিস্ট্রাকচারিংয়েরও সুযোগ দেয়।
type Maybe a
= Nothing --> Variant implies a 'Nothing' function, with type 'Maybe a', and destructuring of 'Nothing'
| Just a --> Variant implies a 'Just' function, with type 'a -> Maybe a', and destructuring of 'Just _'
ডিফল্টভাবে এসব কিছুই ফাইল বা মডিউলের ভেতরের বিষয়, আর কোনটা এক্সপোর্ট করবেন তা বেছে নিতে আমরা exposing কিওয়ার্ড ব্যবহার করি।
একটি অপ্যাক টাইপ তৈরি করতে, আপনি সহজভাবে ভ্যারিয়েন্টগুলো এক্সপোর্ট না করার সিদ্ধান্ত নেন।
এটা করলে, প্রায় সবসময়ই কাস্টম ফাংশন এক্সপোজ করে ভ্যারিয়েন্ট তৈরি ও পাওয়ার আরেকটি উপায় আপনাকে দিতে হয়। এই কাস্টম ফাংশনগুলো ভ্যারিয়েন্ট তৈরি ও পাওয়ার সময় কিছু লজিক প্রয়োগ করার সুযোগ দেয়। এটি মডিউলের অভ্যন্তরীণ ইমপ্লিমেন্টেশনের খুঁটিনাটি লুকিয়ে রাখে, আর এর মানে হলো, এক্সপোজ করা ফাংশনগুলো একই থাকলে আপনি ইমপ্লিমেন্টেশনের খুঁটিনাটি যত খুশি বদলাতে পারেন।
অপ্যাক টাইপের সম্ভবত সবচেয়ে কমন ব্যবহার হলো Parse, dont validate প্যাটার্ন ব্যবহার করে ভ্যালিডেশন প্রয়োগ করা।
এই প্যাটার্নে আপনি এমন একটি ফাংশন এক্সপোজ করেন, যা আপনার চাওয়ার চেয়ে কম স্ট্রাকচার বা টাইপ সেফটিসম্পন্ন একটি ইনপুট নেয়, যেমন একটি String, তারপর সেটিকে আরও বেশি স্ট্রাকচারযুক্ত একটি টাইপে পার্স করে, যেমন EmailAddress, হয় টাইপটি রিটার্ন করে, নয়তো একটি এরর রিটার্ন করে (সাধারণত Maybe বা Result)।
উদাহরণস্বরূপ, নিচের কোডে বাইরের মডিউলগুলোর জন্য parseEmailAddress ফাংশন ব্যবহার করে একটি EmailAddress টাইপ তৈরি করাই শুধু সম্ভব, তাই আপনি যখন EmailAddress টাইপ নিয়ে কাজ করেন, তখন নিশ্চিত থাকতে পারেন যে এটি বৈধ।
module EmailAddress exposing ( EmailAddress, parseEmailAddress, getEmailAddress )
-- The `EmailAddress` custom type has one variant, also called `EmailAddress`
-- When a custom type has one variant, it is idiomatic to use the same name for both.
type EmailAddress =
EmailAddress String
-- create an EmailAddress variant
parseEmailAddress: String -> Maybe EmailAddress
parseEmailAddress candidateEmailAddress =
if isValidEmailAddress candidateEmailAddress then
Just (EmailAddress candidateEmailAddress)
else
Nothing
-- get an EmailAddress variant
getEmailAddress: EmailAddress -> String
getEmailAddress ( EmailAddress emailAdress ) =
emailAdress
isValidEmailAddress: String -> bool
-- ...
এই অনুশীলনীতে আপনি কিছু ধন জমা রাখার জন্য একটি জেনেরিক (/ জাদুকরী!) SecureTreasureChest লিখবেন।
সূক্ষ্মদর্শী শিক্ষার্থীরা খেয়াল করেছেন, আগের TreasureChest আসলে তেমন নিরাপদ ছিল না!
আপনি যদি getTreasure ফাংশনটি ব্যবহার করতেন, তাহলে পাসওয়ার্ড দিতে হতো, কিন্তু পাসওয়ার্ড না জেনেও আপনি শুধু TreasureChest টাইপটি ডিস্ট্রাকচার করে ধনটি পেয়ে যেতে পারতেন।
আরও খারাপ হলো, একই ভাবে আপনি পাসওয়ার্ডটিও বের করে আনতে পারতেন!
চলুন একটি ওপ্যাক টাইপ ব্যবহার করে এটা ঠিক করি।
একটি ভ্যারিয়েন্টসহ একটি Password কাস্টম টাইপ ডিফাইন করুন।
ভ্যারিয়েন্টটির সাথে পাসওয়ার্ডের জন্য একটি অ্যাসোসিয়েটেড String মান থাকবে।
আপনি Password টাইপটি এক্সপোজ করবেন, কিন্তু ভ্যারিয়েন্টটি নয়।
এতে Password একটি ওপ্যাক টাইপ হয়ে যায়, এবং এর মানে হলো পাসওয়ার্ড পেতে আপনি আর ডিস্ট্রাকচারিং ব্যবহার করতে পারবেন না।
কোনো টাইপ ওপ্যাক কি না, তা পরীক্ষা করা সম্ভব নয়। প্রোডাকশন কোডে এটি নিশ্চিত করতে আপনি elm-review (একটি স্ট্যাটিক অ্যানালাইসিস টুল) ব্যবহার করবেন।
একটি টাইপ ডেফিনিশনসহ createPassword ফাংশন ডিফাইন ও এক্সপোজ করুন, যা একটি String নেয় এবং একটি Maybe Password রিটার্ন করে।
Owasp সুপারিশ করে যে পাসওয়ার্ড অন্তত ৮ ক্যারেক্টার লম্বা হওয়া উচিত, তাই এই ইনভ্যারিয়েন্ট নিশ্চিত করতে চলুন Parse, don't validate প্যাটার্নটি ব্যবহার করি।
পাসওয়ার্ড ৮ ক্যারেক্টারের কম হলে createPassword Nothing রিটার্ন করবে, নাহলে Just Password রিটার্ন করবে।
আপনি SecureTreasureChest টাইপটি এক্সপোজ করবেন, কিন্তু ভ্যারিয়েন্টটি নয়।
এতে SecureTreasureChest একটি ওপ্যাক টাইপ হয়ে যায়, এবং এর মানে হলো পাসওয়ার্ড বা ধন পেতে আপনি আর ডিস্ট্রাকচারিং ব্যবহার করতে পারবেন না।
এই ফাংশনটি দুটি প্যারামিটার নেবে এবং এর একটি টাইপ ডেফিনিশন থাকবে।
Password (পাসওয়ার্ডের জন্য)ফাংশনটি একটি SecureTreasureChest রিটার্ন করবে।
এই ফাংশনটি এক্সপোজ করুন, যাতে অন্য মডিউলগুলো SecureTreasureChest-এর ইনস্ট্যান্স তৈরি করতে পারে।
এই ফাংশনটি দুটি প্যারামিটার নেবে এবং এর একটি টাইপ ডেফিনিশন থাকবে।
String (পাসওয়ার্ডের জন্য)SecureTreasureChest জেনেরিক কাস্টম টাইপএই ফাংশনটি SecureTreasureChest-এ থাকা Password-এর সাথে প্রদত্ত পাসওয়ার্ডের চেষ্টাটি মিলিয়ে দেখবে।
ফাংশনটি একটি Maybe রিটার্ন করবে।
পাসওয়ার্ডগুলো মিলে গেলে SecureTreasureChest থেকে পাওয়া জেনেরিক মানটি (ধনটি!) দিয়ে Just রিটার্ন করুন।
পাসওয়ার্ডগুলো না মিললে Nothing রিটার্ন করুন।
এই ফাংশনটি এক্সপোজ করুন, যাতে অন্য মডিউলগুলো সঠিক পাসওয়ার্ড দিলে একটি SecureTreasureChest থেকে ধনটি পেতে পারে।
Exercism-এ সাইন আপ করুন, Elm ট্র্যাকের 28টি কনসেপ্ট110টি অনুশীলনী আর সত্যিকারের মানুষের মেন্টরিং দিয়ে শিখুন ও দক্ষ হয়ে উঠুন, সম্পূর্ণ বিনামূল্যে।