نوع التقاطع
| أنظمة النوع |
|---|
| المفاهيم العامة |
| الفئات الرئيسية |
| الفئات الثانوية |
في نظرية النوع ، يمكن تخصيص نوع تقاطع لقيم يمكن تخصيص كل من النوع والنوع . يمكن إعطاء هذه القيمة نوع التقاطع في نظام نوع التقاطع . [1]
بشكل عام، إذا تداخلت نطاقات قيم نوعين، فيمكن تخصيص نوع التقاطع لهذين النوعين لقيمة تنتمي إلى تقاطع النطاقين. يمكن تمرير مثل هذه القيمة بأمان كحجة إلى الدوال التي تتوقع أيًا من النوعين. على سبيل المثال، في Java، تنفذ الفئة كلًا من الواجهتين و . لذلك، يمكن تمرير كائن من النوع بأمان إلى الدوال التي تتوقع حجة من النوع وإلى الدوال التي تتوقع حجة من النوع .
BooleanSerializableComparableBooleanSerializableComparable
أنواع التقاطع هي أنواع بيانات مركبة . وعلى غرار أنواع المنتجات ، تُستخدم لتعيين عدة أنواع لكائن. ومع ذلك، يتم تعيين أنواع المنتجات إلى مجموعات ، بحيث يتم تعيين مكون نوع منتج معين لكل عنصر من عناصر المجموعة. وبالمقارنة، فإن الكائنات الأساسية لأنواع التقاطع ليست بالضرورة مركبة. وهناك شكل مقيد لأنواع التقاطع وهو أنواع التحسين .
تُعد أنواع التقاطع مفيدة لوصف الدوال المثقلة . [2] على سبيل المثال، إذا كان نوع الدالة هو الذي يأخذ رقمًا كوسيطة ويعيد رقمًا، وكان نوع الدالة هو الذي يأخذ سلسلة كوسيطة ويعيد سلسلة، فيمكن استخدام تقاطع هذين النوعين لوصف الدوال (المثقلة) التي تقوم بأحد الأمرين أو الآخر، بناءً على نوع الإدخال المعطى لها.
number => numberstring => string
تستخدم لغات البرمجة المعاصرة، بما في ذلك Ceylon وFlow و Java و Scala و TypeScript و Whiley (انظر مقارنة اللغات بأنواع التقاطع)، أنواع التقاطع لدمج مواصفات الواجهة والتعبير عن تعدد الأشكال المخصص . واستكمالاً لتعدد الأشكال البارامترية ، يمكن استخدام أنواع التقاطع لتجنب تلوث التسلسل الهرمي للفئة من المخاوف المتقاطعة والحد من الكود النمطي ، كما هو موضح في مثال TypeScript أدناه.
يشار إلى الدراسة النظرية لأنواع التقاطعات باسم تخصص نوع التقاطع . [3] ومن المثير للدهشة أنه يمكن وصف إنهاء البرنامج بدقة باستخدام أنواع التقاطع. [4]
مثال على TypeScript
يدعم TypeScript أنواع التقاطع، [5] مما يحسن من قدرة نظام النوع على التعبير ويقلل من حجم التسلسل الهرمي المحتمل للفئة، كما هو موضح على النحو التالي.
يعرّف كود البرنامج التالي الفئات Chickenو Cowو RandomNumberGeneratorوأن كل منها تحتوي على طريقة produceتعيد كائنًا من النوع Eggأو Milkأو number. بالإضافة إلى ذلك، تتطلب الوظائف eatEggو drinkMilkوسيطات من النوع Eggو Milkعلى التوالي.
الفئة Egg { نوع خاص : "Egg" } الفئة Milk { نوع خاص : "Milk" }
// ينتج بيضًا
class Chicken { produce () { return new Egg (); } }
// تنتج حليبًا
class Cow { produce () { return new Milk (); } }
// ينتج رقمًا عشوائيًا
class RandomNumberGenerator { produce () { return Math . random (); } }
// يتطلب دالة البيض eatEgg ( egg : Egg ) { return "لقد أكلت بيضة." ; }
// يتطلب
وظيفة الحليب drinkMilk ( milk : Milk ) { return "لقد شربت بعض الحليب." ; }
يحدد كود البرنامج التالي الدالة المتعددة الأشكال المخصصةanimalToFood التي تستدعي الدالة العضو produceللكائن المعطى . تحتوي animalالدالة على تعليقين للنوع، وهما و ، متصلان عبر منشئ نوع التقاطع . على وجه التحديد، عند تطبيقها على وسيطة من النوع، تعيد كائنًا من النوع ، وعند تطبيقها على وسيطة من النوع، تعيد كائنًا من النوع . من الناحية المثالية، لا ينبغي تطبيقها على أي كائن يحتوي (ربما عن طريق الصدفة) على طريقة.
animalToFood((_: Chicken) => Egg)((_: Cow) => Milk)&animalToFoodChickenEggCowMilkanimalToFoodproduce
// إذا أعطيت دجاجة، تنتج بيضة؛ وإذا أعطيت بقرة، تنتج حليبًا .
لنفترض أن animalToFood : (( _ : Chicken ) => Egg ) & (( _ : Cow ) => Milk ) = function ( animal : any ) { return animal . produce (); };
أخيرًا، يوضح كود البرنامج التالي الاستخدام الآمن للأنواع الخاصة بالتعريفات المذكورة أعلاه.
var chicken = new Chicken ();
var cow = new Cow ();
var randomNumberGenerator = new RandomNumberGenerator ();
console.log ( chicken.product ()) ; // بيضة { }
console.log ( cow.product ()) ; // حليب { }
console.log ( randomNumberGenerator.product ( ) ) ; //0.2626353555444987
console.log ( animalToFood ( دجاج ) ) ; //بيضة { }
console.log ( animalToFood ( cow )); // الحليب { }
//console.log(animalToFood(randomNumberGenerator)); // خطأ: لا يمكن تعيين وسيطة من النوع 'RandomNumberGenerator' إلى معلمة من النوع 'Cow'
console .log ( eatEgg ( animalToFood ( دجاج ))); // لقد أكلت بيضة .
//console.log(eatEgg(animalToFood(cow))); // خطأ: لا يمكن تعيين وسيطة من النوع 'Milk' إلى معلمة من النوع 'Egg'
console.log ( drankMilk ( animalToFood ( cow ) )); // شربت بعض الحليب.
//console.log(drinkMilk(animalToFood(chicken))); // خطأ: لا يمكن تعيين وسيطة من النوع 'Egg' إلى معلمة من النوع 'Milk'
يحتوي كود البرنامج أعلاه على الخصائص التالية:
- تُنشئ الأسطر من 1 إلى 3 الكائنات
chicken،cow، وrandomNumberGeneratorمن نوعها الخاص. - تطبع الأسطر من 5 إلى 7 النتائج الخاصة بالأشياء التي تم إنشاؤها مسبقًا (يتم توفيرها كتعليقات) عند استدعاء
produce. - يوضح السطر 9 (أو 10) الاستخدام الآمن للنوع للطريقة
animalToFoodالمطبقة علىchicken(أوcow). - يؤدي عدم التعليق على السطر 11 إلى حدوث خطأ في النوع في وقت التجميع. وعلى الرغم من أن تنفيذ يمكن
animalToFoodأن يستدعيproduceطريقةrandomNumberGenerator، فإن التعليق التوضيحي للنوع لاanimalToFoodيسمح بذلك. وهذا يتفق مع المعنى المقصود منanimalToFood. - يوضح السطر 13 (أو 15) أن تطبيقه
animalToFoodعلىchicken(أوcow) يؤدي إلى إنشاء كائن من نوعEgg(أوMilk). - يوضح السطر 14 (أو 16) أن التطبيق
animalToFoodعلىcow(أوchicken). لا يؤدي إلى إنشاء كائن من النوعEgg(أوMilk). لذلك، إذا لم يتم التعليق على السطر 14 (أو 16) فسيؤدي ذلك إلى حدوث خطأ في النوع في وقت التجميع.
مقارنة بالميراث
يمكن تحقيق المثال البسيط أعلاه باستخدام الميراث ، على سبيل المثال عن طريق اشتقاق الفئات Chickenو Cowمن فئة أساسية Animal. ومع ذلك، في بيئة أكبر، قد يكون هذا غير مفيد. لا يُبرر بالضرورة تقديم فئات جديدة في التسلسل الهرمي للفئات لأسباب متقاطعة ، أو ربما يكون مستحيلًا تمامًا، على سبيل المثال عند استخدام مكتبة خارجية. يمكن تصور المثال أعلاه بالفئات التالية:
- فئة
Horseليس لهاproduceطريقة؛ - فئة
Sheepتحتوي علىproduceطريقة إرجاعWool؛ - فئة
Pigتحتوي علىproduceطريقة يمكن استخدامها مرة واحدة فقط، وترجعMeat.
قد يتطلب هذا فئات إضافية (أو واجهات) تحدد ما إذا كانت طريقة الإنتاج متاحة، وما إذا كانت طريقة الإنتاج تعيد الطعام، وما إذا كان من الممكن استخدام طريقة الإنتاج بشكل متكرر. بشكل عام، قد يؤدي هذا إلى تلويث التسلسل الهرمي للفئات.
مقارنة بكتابة البطة
يُظهِر المثال البسيط أعلاه بالفعل أن كتابة duck أقل ملاءمة لتحقيق السيناريو المعطى. في حين RandomNumberGeneratorتحتوي الفئة على طريقة، لا ينبغي أن يكون produceالكائن وسيطة صالحة لـ . يمكن تحقيق المثال أعلاه باستخدام كتابة duck، على سبيل المثال عن طريق إدخال حقل جديد إلى الفئات والإشارة إلى أن الكائنات من النوع المقابل هي وسيطات صالحة لـ . ومع ذلك، لن يؤدي هذا إلى زيادة حجم الفئات المعنية فحسب (خاصةً مع إدخال المزيد من الطرق المشابهة لـ )، ولكنه أيضًا نهج غير محلي فيما يتعلق بـ .
randomNumberGeneratoranimalToFoodargumentForAnimalToFoodChickenCowanimalToFoodanimalToFoodanimalToFood
مقارنة مع التحميل الزائد للوظيفة
يمكن تنفيذ المثال أعلاه باستخدام التحميل الزائد للوظيفة ، على سبيل المثال عن طريق تنفيذ طريقتين و . في TypeScript، يكون هذا الحل متطابقًا تقريبًا مع المثال المقدم. تتطلب لغات البرمجة الأخرى، مثل Java ، تنفيذات مميزة للطريقة المحملة. قد يؤدي هذا إلى تكرار الكود أو كود نمطي .
animalToFood(animal: Chicken): EgganimalToFood(animal: Cow): Milk
مقارنة بنمط الزائر
يمكن تنفيذ المثال أعلاه باستخدام نمط الزائر . سيتطلب ذلك من كل فئة حيوانية تنفيذ acceptطريقة تقبل كائنًا ينفذ الواجهة (إضافة كود نمطيAnimalVisitor غير محلي ). سيتم تنفيذ الوظيفة كطريقة لتنفيذ . لسوء الحظ، سيكون من الصعب تمثيل
الاتصال بين نوع الإدخال ( أو ) ونوع النتيجة ( أو ).animalToFoodvisitAnimalVisitorChickenCowEggMilk
القيود
من ناحية أخرى، يمكن استخدام أنواع التقاطع لشرح أنواع مختلفة من الدالة محليًا دون تقديم فئات (أو واجهات) جديدة إلى التسلسل الهرمي للفئة. من ناحية أخرى، يتطلب هذا النهج تحديد جميع أنواع الحجج وأنواع النتائج المحتملة صراحةً. إذا كان من الممكن تحديد سلوك الدالة بدقة إما من خلال واجهة موحدة أو تعدد الأشكال البارامترية أو الكتابة العشوائية ، فإن الطبيعة المطولة لأنواع التقاطع غير مواتية. لذلك، يجب اعتبار أنواع التقاطع مكملة لطرق المواصفات الحالية.
نوع التقاطع المعتمد
نوع التقاطع التابع ، والذي يُشار إليه بـ ، هو نوع تابع حيث قد يعتمد النوع على متغير المصطلح . [6] وعلى وجه الخصوص، إذا كان للمصطلح نوع التقاطع التابع ، فإن المصطلح يحتوي على كل من النوع والنوع ، حيث هو النوع الذي ينتج عن استبدال جميع حالات متغير المصطلح في بالمصطلح .
مثال سكالا
تدعم لغة سكالا إعلانات النوع [7] كأعضاء كائن. وهذا يسمح لنوع عضو كائن بالاعتماد على قيمة عضو آخر، وهو ما يسمى بالنوع المعتمد على المسار . [8]
على سبيل المثال، يحدد نص البرنامج التالي سمة سكالا Witness، والتي يمكن استخدامها لتنفيذ نمط المفرد . [9]
السمة الشاهد { النوع T القيمة القيمة : T {} }
تعلن السمة أعلاه Witnessعن العضو T، والذي يمكن تعيين نوع له كقيمة، والعضو value، والذي يمكن تعيين قيمة من النوع T. يحدد نص البرنامج التالي كائنًا booleanWitnessكمثال للسمة أعلاه Witness. يحدد الكائن booleanWitnessالنوع Tكـ Booleanوالقيمة valueكـ true. على سبيل المثال، تنفيذ عمليات الطباعة على وحدة التحكم.
System.out.println(booleanWitness.value)true
الكائن booleanWitness يمتد Witness { النوع T = Boolean val value = true }
ليكن نوع (على وجه التحديد، نوع سجل ) الكائنات التي لها العضو من النوع . في المثال أعلاه، يمكن تعيين نوع التقاطع التابع للكائن . والمنطق هو كما يلي. يحتوي الكائن على العضو الذي تم تعيين النوع له كقيمة له. بما أن هو نوع، فإن الكائن يحتوي على النوع . بالإضافة إلى ذلك، يحتوي الكائن على العضو الذي تم تعيين قيمة النوع له . وبما أن قيمة هي ، فإن الكائن يحتوي على النوع . بشكل عام، يحتوي الكائن على نوع التقاطع . لذلك، عند تقديم المرجع الذاتي كاعتماد، فإن الكائن يحتوي على نوع التقاطع التابع .
booleanWitnessbooleanWitnessTBooleanBooleanbooleanWitnessbooleanWitnessvaluetrueBooleanbooleanWitness.TBooleanbooleanWitnessbooleanWitnessbooleanWitness
بدلاً من ذلك، يمكن وصف المثال البسيط أعلاه باستخدام أنواع السجلات التابعة . [10] بالمقارنة مع أنواع التقاطع التابعة، تشكل أنواع السجلات التابعة مفهومًا نظريًا متخصصًا بشكل صارم. [6]
تقاطع عائلة النوع
تقاطع عائلة النوع ، والذي يُشار إليه بـ ، هو نوع تابع حيث قد يعتمد النوع على متغير المصطلح . على وجه الخصوص، إذا كان للمصطلح النوع ، فبالنسبة لكل مصطلح من النوع ، يكون للمصطلح النوع . يُطلق على هذا المفهوم أيضًا نوع باي الضمني ، [11] مع ملاحظة أن الوسيطة لا يتم الاحتفاظ بها على مستوى المصطلح.
مقارنة اللغات ذات أنواع التقاطع
| لغة | تم تطويره بشكل نشط | النموذج(النماذج) | حالة | سمات |
|---|---|---|---|---|
| سي شارب | نعم [12] | قيد المناقشة [13] | بالإضافة إلى ذلك، يمكن أن تحتوي معلمات النوع العام على قيود تتطلب من وسيطات النوع (الموحدة الشكل) الخاصة بها تنفيذ واجهات متعددة، حيث يصبح نوع وقت التشغيل الذي يمثله معلمة النوع العام نوع تقاطع لجميع الواجهات المدرجة. | |
| سيلان | لا [14] | مدعوم [15] |
| |
| ف# | نعم [16] | قيد المناقشة [17] | ؟ | |
| تدفق | نعم [18] | مدعوم [19] |
| |
| فورسيث | لا | مدعوم [20] |
| |
| جافا | نعم [21] | مدعوم [22] |
| |
| بي اتش بي | نعم [23] | مدعوم [24] |
| |
| سكالا | نعم [25] | مدعوم [26] [27] |
| |
| تايب سكريبت | نعم [28] | مدعوم [5] |
| |
| بينما | نعم [29] | مدعوم [30] | ؟ |
مراجع
- ^ باريندريجت، هنك؛ كوبو، ماريو؛ ديزاني-سيانكاجليني، ماريانجيولا (1983). "نموذج لامدا المرشح واكتمال تعيين النوع". مجلة المنطق الرمزي . 48 (4): 931-940. doi :10.2307/2273659. JSTOR 2273659. S2CID 45660117.
- ^ Palsberg, Jens (2012). "Overloading is NP-Complete". Logic and Program Semantics . Lecture Notes in Computer Science. المجلد 7230. ص 204-218. doi :10.1007/978-3-642-29485-3_13. ISBN 978-3-642-29484-6.
- ^ هينك باريندريجت. ويل ديكرز؛ ريتشارد ستاتمان (20 يونيو 2013). حساب التفاضل والتكامل لامدا مع الأنواع. مطبعة جامعة كامبريدج. ص 1 –. رقم ISBN 978-0-521-76614-2.
- ^ Ghilezan, Silvia (1996). "Strong normalization and typeability with intersection types". مجلة نوتردام للمنطق الرسمي . 37 (1): 44–52. doi : 10.1305/ndjfl/1040067315 .
- ^ "أنواع التقاطعات في TypeScript" . تم الاسترجاع في 2019-08-01 .
- ^ ab Kopylov, Alexei (2003). "التقاطع التابع: طريقة جديدة لتعريف السجلات في نظرية النوع". ندوة معهد مهندسي الكهرباء والإلكترونيات الثامنة عشر حول المنطق في علوم الكمبيوتر . LICS 2003. جمعية IEEE للكمبيوتر. ص. 86-95. CiteSeerX 10.1.1.89.4223 . doi :10.1109/LICS.2003.1210048.
- ^ "إعلانات النوع في سكالا" . تم الاسترجاع في 2019-08-15 .
- ^ أمين، نادا؛ جروتر، صموئيل؛ أوديرسكي، مارتن؛ رومبف، تيارك؛ ستوكي، ساندرو (2016). "جوهر أنواع الكائنات التابعة". قائمة النجاحات التي يمكن أن تغير العالم (PDF) . مذكرات محاضرات في علوم الكمبيوتر. المجلد 9600. سبرينغر. ص 249-272. doi :10.1007/978-3-319-30936-1_14. ISBN 978-3-319-30935-4.
- ^ "Singletons في مكتبة Scala عديمة الشكل". GitHub . تم الاسترجاع في 2019-08-15 .
- ^ بولاك، روبرت (2000). "السجلات المصنفة تبعًا لتمثيل البنية الرياضية". إثبات النظرية في المنطق من الدرجة الأعلى، المؤتمر الدولي الثالث عشر . TPHOLs 2000. سبرينغر. ص. 462-479. doi :10.1007/3-540-44659-1_29.
- ^ ستامب، آرون (2018). "من إمكانية التحقيق إلى الاستدلال عبر التقاطع التابع". حوليات المنطق النقي والتطبيقي . 169 (7): 637-655. doi : 10.1016/j.apal.2018.03.002 .
- ^ "دليل C#" . تم الاسترجاع في 2019-08-08 .
- ^ "مناقشة: أنواع الاتحاد والتقاطع في لغة سي شارب". GitHub . تم الاسترجاع في 2019-08-08 .
- ^ "Eclipse Ceylon™". 19 يوليو 2017. تم الاسترجاع في 2023-08-16 .
- ^ "أنواع التقاطعات في سيلان". 19 يوليو 2017. تم الاسترجاع 2019-08-08 .
- ^ "F# Software Foundation" . تم الاسترجاع في 2019-08-08 .
- ^ "إضافة أنواع التقاطعات إلى F Sharp". GitHub . تم الاسترجاع في 2019-08-08 .
- ^ "Flow: A Static Type Checker for JavaScript". مؤرشف من الأصل في 2022-04-08 . تم الاسترجاع في 2019-08-08 .
- ^ "قواعد نوع التقاطع في التدفق" . تم الاسترجاع في 2019-08-08 .
- ^ رينولدز، جيه سي (1988). التصميم الأولي للغة البرمجة فورسيث.
- ^ "برمجيات جافا" . تم الاسترجاع في 2019-08-08 .
- ^ "IntersectionType (Java SE 12 & JDK 12)" . تم الاسترجاع في 2019-08-01 .
- ^ "php.net".
- ^ "PHP.Watch - PHP 8.1: أنواع التقاطع".
- ^ "لغة البرمجة سكالا" . تم الاسترجاع في 2019-08-08 .
- ^ "أنواع المركبات في سكالا" . تم الاسترجاع في 2019-08-01 .
- ^ "أنواع التقاطعات في دوتي" . تم الاسترجاع في 2019-08-01 .
- ^ "TypeScript - JavaScript that scales" . تم الاسترجاع في 2019-08-01 .
- ^ "Whiley: لغة برمجة مفتوحة المصدر مع فحص ثابت ممتد" . تم الاسترجاع في 2019-08-01 .
- ^ "مواصفات لغة وايلي" (PDF) . تم الاسترجاع في 2019-08-01 .
