الأنواع المعتمة هي تقنية للتغليف في Elm.
ويسميها بعض الناس أيضًا إخفاء المعلومات، أو إخفاء تفاصيل التنفيذ.
وهي تُستخدم أيضًا كثيرًا لفرض التحقق، باستخدام نمط التحليل، لا التحقق.
على سبيل المثال، يمكن أن يكون لديك نوع معتم 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 لاختيار ما نريد تصديره.
تُظهر وحدة Maybe النوع Maybe (كي تتمكن الوحدات الأخرى من استخدام قيم Maybe الموجودة)، وتُظهر أيضًا الصيغتين Nothing وJust (كي تتمكن الوحدات الأخرى من إنشاء قيم Maybe وتفكيكها).
وهي تستخدم الصياغة التالية لفعل ذلك.
يخبر الجزء Maybe(..) لغة Elm أن تُظهر كل الصيغ، إضافة إلى تعريف النوع المخصص.
module Maybe exposing
( Maybe(..)
-- ...
)
لإنشاء نوع معتم، ما عليك سوى ألا تصدّر الصيغ.
ولفعل ذلك مع النوع Maybe، ستستخدم الصياغة التالية:
module Maybe exposing
( Maybe
-- ...
)
عندما تفعل ذلك، ستحتاج غالبًا إلى توفير وسيلة أخرى لإنشاء الصيغ والحصول عليها، وذلك بإظهار دوال مخصصة. تتيح لك هذه الدوال المخصصة تطبيق بعض المنطق عند إنشاء الصيغ والحصول عليها. وهذا يخفي تفاصيل التنفيذ الداخلية للوحدة، ويعني أنه يمكنك تغيير تفاصيل التنفيذ كما تشاء، ما دامت الدوال المُظهَرة تبقى كما هي. كما يتيح لك الحفاظ على الثوابت عند إنشاء النوع واستخدامه.
على الأرجح، أكثر استخدامات الأنواع المعتمة شيوعًا هو فرض التحقق، باستخدام نمط التحليل، لا التحقق.
في هذا النمط، تُظهر دالة تأخذ مُدخلًا ببنية أو أمان أنواع أقل مما تريد، مثل String، ثم تحلّله إلى نوع أكثر بنية، مثل EmailAddress، فإما أن تُرجع النوع، وإما أن تُرجع خطأ (غالبًا Maybe أو Result).
على سبيل المثال، في الكود أدناه، لا يمكن للوحدات الخارجية إنشاء نوع EmailAddress إلا باستخدام الدالة parseEmailAddress، لذا عندما تعمل مع النوع 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
-- ...