نوع الخيار

في لغات البرمجة (وخاصةً لغات البرمجة الوظيفية ) ونظرية الأنواع ، يُعدّ نوع الخيار أو نوع "ربما" نوعًا متعدد الأشكال يُمثّل تغليفًا لقيمة اختيارية؛ على سبيل المثال، يُستخدم كنوع إرجاع للدوال التي قد تُرجع أو لا تُرجع قيمة ذات معنى عند تطبيقها. ويتكوّن من مُنشئ إما أن يكون فارغًا (يُسمى غالبًا فارغًا Noneأو Nothingغير فارغ)، أو يُغلّف نوع البيانات الأصلي A(يُكتب غالبًا فارغًا Just Aأو غير فارغ Some A).

هناك مفهومٌ آخر، وإن كان ذا صلة، خارج نطاق البرمجة الوظيفية، وشائع في البرمجة الكائنية ، يُسمى الأنواع القابلة للتصفير (ويُعبَّر عنها غالبًا بـ A?). ويكمن الفرق الأساسي بين أنواع الخيارات والأنواع القابلة للتصفير في أن أنواع الخيارات تدعم التداخل (مثل Maybe (Maybe String)Maybe String)، بينما لا تدعمه الأنواع القابلة للتصفير (مثل String??= String?).

الجوانب النظرية

في نظرية الأنواع ، يمكن كتابتها على النحو التالي:أ؟=أ+1{\displaystyle A^{?}=A+1}وهذا يعبر عن حقيقة أنه بالنسبة لمجموعة معينة من القيم فيأ{\displaystyle A}يضيف نوع الخيار قيمة إضافية واحدة فقط (القيمة الفارغة) إلى مجموعة القيم الصالحة لـأ{\displaystyle A}ينعكس هذا في البرمجة من خلال حقيقة أنه في اللغات التي تحتوي على اتحادات مُوسومة ، يمكن التعبير عن أنواع الخيارات كاتحاد مُوسوم للنوع المُغلّف بالإضافة إلى نوع الوحدة . [ 1 ] يُعد نوع الخيار حالة خاصة من الاتحاد المُوسوم، حيث Nothingيُؤخذ كنوع أحادي (منشئ صفري لـ) نوع أحادي. يمكن عمومًا تنفيذ الاتحادات المُوسومة من خلال مزيج من أنواع الاتحاد وأنواع السجلات باستخدام كتابة التكرار . [ 2 ]

نوع الخيار هو أيضًا موناد حيث: [ 3 ]

return = Just -- يغلّف القيمة في احتماللا شيء >>= f = لا شيء -- يفشل إذا فشلت الموناد السابقة ( فقط x ) >>= f = f x -- ينجح عندما تنجح كلتا المونادتين

تُعد الطبيعة الأحادية لنوع الخيار مفيدة لتتبع حالات الفشل والأخطاء بكفاءة. [ 4 ]

أمثلة

آدا

لا تُطبّق لغة Ada أنواع الخيارات مباشرةً، ولكنها تُوفّر أنواعًا مُميّزة يُمكن استخدامها لتعيين معلمات السجل. لتطبيق نوع خيار، يُستخدم نوع منطقي كمُميّز؛ يُقدّم المثال التالي نموذجًا عامًا لإنشاء نوع خيار من أي نوع مُقيّد غير محدود:

عام -- أي نوع مقيد وغير محدود. نوع Element_Type خاص ؛ حزمة Optional_Type هي -- عندما يكون المُميز Has_Element صحيحًا، يوجد حقل عنصر، -- عندما يكون خاطئًا، لا توجد حقول (ومن هنا الكلمة المفتاحية null). نوع Optional ( Has_Element : منطقي ) هو سجل حالة Has_Element هي عندما يكون خطأ => Null ؛ عندما يكون صحيحًا => Element : Element_Type ؛ نهاية الحالة ؛ نهاية السجل ؛ نهاية Optional_Type ؛

مثال على الاستخدام:

package Optional_Integers is new Optional_Type ( Element_Type => Integer ); Foo : Optional_Integers . Optional := ( Has_Element => True , Element => 5 ); Bar : Optional_Integers . Optional := ( Has_Element => False );

أغدا

في لغة أغدا، يتم تسمية نوع الخيار Maybeباستخدام المتغيرات nothingو .justa

نظام تتبع التطبيقات

في نظام ATS، يتم تعريف نوع الخيار على النحو التالي:

datatype option_t0ype_bool_type ( a : t @ ype +, bool ) = | Some ( a , true ) of a | None ( a , false ) stadef option = option_t0ype_bool_type typedef Option ( a : t @ ype ) = [ b : bool ] option ( a , b )
# تضمين "share/atspre_staload.hats"دالة ` show_value` ( opt : Option int ): string = case + opt of | None () => "لا توجد قيمة" | Some ( s ) => tostring_int simplement main0 () : void = let val full = Some42 and empty = None in println !( "show_value full → " , show_value full ) ; println !( "show_value empty → " , show_value empty ); end
عرض القيمة كاملة ← 42 عرض القيمة فارغة ← لا توجد قيمة

لغة سي++

منذ C++17، يتم تعريف نوع الخيار في المكتبة القياسية على النحو التالي : [ 5 ]template<typenameT>optional<T>

استيراد std ؛باستخدام std :: nullopt ؛ باستخدام std :: optional ؛constexpr optional < double > divide ( double x , double y ) noexcept { if ( y != 0.0 ) { return x / y ; }return nullopt ; }void readDivisionResults ( int x , int y ) { optional <double> result = divide ( x , y ) ; if ( result ) { std :: println ( "ناتج قسمة x: {} على y: {} هو {}." , x , y , result.value ( ) ); } else { std :: println ( " ناتج قسمة x: {} على y: {} غير مُعرَّف!" , x , y ); } }int main ( int argc , char * argv []) { readDivisionResults ( 1 , 5 ); readDivisionResults ( 8 , 0 ); }

في C++23std::optional<T> ، يتوفر دعم العمليات الأحادية لـ . [ 5 ]

إلم

في لغة Elm، يتم تعريف نوع الخيار على النحو التالي : [ 6 ]typeMaybea=Justa|Nothing

فا#

في لغة F#، يتم تعريف نوع الخيار على النحو التالي : [ 7 ]type'aoption=None|Someof'a

let showValue = Option.fold ( fun_x - > sprintf "القيمة هي: %d" x ) " لا توجد قيمة "let full = Some 42 let empty = Noneعرض القيمة الكاملة |> printfn "عرض القيمة الكاملة -> %s" عرض القيمة الفارغة |> printfn "عرض القيمة الفارغة -> %s"
عرض القيمة كاملة -> القيمة هي: 42 عرض القيمة فارغة -> لا توجد قيمة

هاسكل

في لغة هاسكل ، يتم تعريف نوع الخيار على النحو التالي : [ 8 ]dataMaybea=Nothing|Justa

showValue :: Maybe Int -> String showValue = foldl ( \ _ x -> "القيمة هي: " ++ show x ) "لا توجد قيمة"main :: IO () main = do let full = Just 42 let empty = NothingputStrLn $ "showValue full -> " ++ showValue full putStrLn $ "showValue empty -> " ++ showValue empty
عرض القيمة كاملة -> القيمة هي: 42 عرض القيمة فارغة -> لا توجد قيمة

إدريس

في إدريس، يتم تعريف نوع الخيار على النحو التالي :dataMaybea=Nothing|Justa

showValue : Maybe Int -> String showValue = foldl (\ _ , x => "القيمة هي " ++ show x ) "لا توجد قيمة"الدالة الرئيسية : IO () main = do let full = Just 42 let empty = NothingputStrLn $ "showValue full -> " ++ showValue full putStrLn $ "showValue empty -> " ++ showValue empty 
عرض القيمة كاملة -> القيمة هي: 42 عرض القيمة فارغة -> لا توجد قيمة

جافا

في لغة جافا، يتم تعريف نوع الخيار بواسطة الفئة في المكتبة القياسية .java.util.Optional<T>

استيراد java.util.Optional ;public class OptionExample { static String showValue ( Optional < Integer > opt ) { return opt . map ( x -> String . format ( "القيمة هي: %d" , x )). orElse ( "لا توجد قيمة" ); }public static void main ( String [] args ) { Optional < Integer > full = Optional . of ( 42 ); Optional < Integer > empty = Optional . empty ();System.out.printf ( "showValue(full): %s\n" , showValue ( full ) ) ; System.out.printf ( " showValue ( empty): %s\n " , showValue ( empty ) ) ; } }
عرض القيمة كاملة -> القيمة هي: 42 عرض القيمة فارغة -> لا توجد قيمة

نيم

استيراد std / خياراتproc showValue ( opt : Option [ int ] ): string = opt . map ( proc ( x : int ): string = "القيمة هي: " & $ x ). get ( "لا توجد قيمة" )let full = some ( 42 ) empty = none ( int )echo "showValue(full) -> " , showValue ( full ) echo "showValue(empty) -> " , showValue ( empty )
showValue(full) -> القيمة هي: 42 showValue(empty) -> لا توجد قيمة

أوكاميل

في لغة OCaml، يتم تعريف نوع الخيار على النحو التالي : [ 9 ]type'aoption=None|Someof'a

let show_value = Option.fold ~ none : "لا توجد قيمة" ~ some : ( fun x -> " القيمة هي: " ^ string_of_int x )let () = let full = Some 42 in let empty = None inprint_endline ( "show_value full -> " ^ show_value full ); print_endline ( "show_value empty -> " ^ show_value empty )
show_value full -> القيمة هي: 42 show_value empty -> لا توجد قيمة

روك

في Rocq ، يتم تعريف نوع الخيار على النحو التالي :Inductiveoption(A:Type):Type:=|Some:A->optionA|None:optionA.

الصدأ

في لغة Rust، يتم تعريف نوع الخيار على النحو التالي : [ 10 ]enumOption<T>{None,Some(T)}

fn show_value ( opt : Option < i32 > ) -> String { opt . map_or ( "لا توجد قيمة" . to_owned (), | x : i32 | format! ( "القيمة هي: {}" , x )) }fn main () { let full : Option < i32 > = Some ( 42 ); let empty : Option < i32 > = None ;println! ( "show_value(full) -> {}" , show_value ( full )); println! ( "show_value(empty) -> {}" , show_value ( empty )); }
show_value(full) -> القيمة هي: 42 show_value(empty) -> لا توجد قيمة

سكالا

في لغة سكالا، يتم تعريف نوع الخيار على أنه ، وهو نوع ممتد بواسطة و .sealedabstractclassOption[+A]finalcaseclassSome[+A](value:A)caseobjectNone

object Main : def showValue ( opt : Option [ Int ]): String = opt . fold ( "لا توجد قيمة" )( x => s"القيمة هي: $ x " )def main ( args : Array [ String ]): Unit = val full = Some ( 42 ) val empty = Noneprintln ( s"showValue(full) -> ${ showValue ( full ) } " ) println ( s"showValue(empty) -> ${ showValue ( empty ) } " )
showValue(full) -> القيمة هي: 42 showValue(empty) -> لا توجد قيمة

لغة الآلة القياسية

في لغة ML القياسية، يتم تعريف نوع الخيار على النحو التالي :datatype'aoption=NONE|SOMEof'a

سويفت

في لغة Swift، يتم تعريف نوع الخيار على أنه ولكن يتم كتابته بشكل عام على النحو التالي : [ 11 ]enumOptional<T>{casenone,some(T)}T?

func showValue ( _ opt : Int ?) -> String { return opt.map { "القيمة هي: \( $ 0 ) " } ?? "لا توجد قيمة" }let full = 42 let empty : Int ? = nilprint ( "showValue(full) -> \( showValue ( full )) " ) print ( "showValue(empty) -> \( showValue ( empty )) " )
showValue(full) -> القيمة هي: 42 showValue(empty) -> لا توجد قيمة

زيج

في لغة Zig، أضف  علامة استفهام قبل اسم النوع ?i32لجعله نوعًا اختياريًا.

يمكن التقاط الحمولة n في عبارة if أو while ، مثل ، ويتم تقييم عبارة else إذا كانت كذلك .if(opt)|n|{...}else{...}null

const std = @import ( "std" );fn showValue ( gpa : std.mem.Allocator , opt : ? i32 ) ! [] u8 { return if ( opt ) | n | std.fmt.allocPrint ( gpa , " القيمة هي: { } " , . { n } ) else gpa.dupe ( u8 , " لا توجد قيمة " ) ; }pub fn main ( init : std . process . Init ) ! void { // تجهيز دفق الإخراج القياسي. var buffer : [ 1024 ] u8 = undefined ; var writer = std . Io . File . stdout (). writer ( init . io , & buffer );// نفّذ مثالنا. const full = 42 ; const empty = null ;const full_msg = try showValue ( init.gpa , full ); defer init.gpa.free ( full_msg ) ; try writer.interface.print ( " showValue (init.gpa, full) -> { s } \ n " , . { full_msg } ) ;const empty_msg = try showValue ( init.gpa , empty ) ; defer init.gpa.free ( empty_msg ) ; try writer.interface.print ( " showValue (init.gpa, empty) -> { s } \ n " , . { empty_msg } ) ;حاول تنفيذ الأمر التالي : ` writer.interface.flush (); `
showValue(init.gpa, full) -> القيمة هي: 42 showValue(init.gpa, empty) -> لا توجد قيمة

انظر أيضاً

مراجع

  1. ميليفسكي، بارتوش (13 يناير 2015). "أنواع البيانات الجبرية البسيطة" . مقهى بارتوش ميليفسكي للبرمجة . أنواع الجمع. "كان بإمكاننا ترميز Maybe على النحو التالي: data Maybe a = Either () a". مؤرشف من الأصل في 18 أغسطس 2019. تم الاسترجاع في 18 أغسطس 2019 .
  2. https://arxiv.org/pdf/2111.03354 ص 8
  3. "قبضة من المونادات - تعلم لغة هاسكل من أجل الخير العظيم!" . www.learnyouahaskell.com . تم الاطلاع عليه بتاريخ 18 أغسطس 2019 .
  4. هاتون، غراهام (25 نوفمبر 2017). "ما هي الموناد؟" . قناة Computerphile على يوتيوب . مؤرشف من الأصل بتاريخ 20 ديسمبر 2021. تم الاطلاع عليه بتاريخ 18 أغسطس 2019 .
  5. 1 2 "std::optional - cppreference.com" . docs.cppreference.com . تم الاسترجاع في 2026-01-06 .
  6. "ربما · مقدمة إلى لغة إلم" . guide.elm-lang.org .
  7. "خيارات" . fsharp.org . تم الاطلاع عليه بتاريخ 2024-10-08 .
  8. "6 أنواع وفئات مُعرَّفة مسبقًا" . Haskell.org . تم الاطلاع عليه بتاريخ 15-06-2022 .
  9. "مكتبة OCaml : الخيار" . v2.ocaml.org . تم الاسترجاع في 15-06-2022 . 
  10. "Option in core::option - Rust" . doc.rust-lang.org . 2022-05-18 . تم الاطلاع عليه بتاريخ 2022-06-15 .
  11. "وثائق مطوري Apple" . developer.apple.com . تم الاطلاع عليه بتاريخ 2020-09-06 .