مرحبا يا هبر! نحن نعود متأخرا بعض الشيء من عطلة العام الجديد مع استمرار سلسلة مقالاتنا حول البرمجة الوظيفية. اليوم سنتحدث عن فهم الوظائف من خلال التواقيع وتحديد أنواعك الخاصة لتوقيعات الوظائف. التفاصيل تحت خفض!

غير واضح ، ولكن F # له بناءان: تعبيرات عادية (ذات معنى) ولتعريفات النوع. على سبيل المثال:
[1;2;3] // int list // Some 1 // int option // (1,"a") // int * string //
تحتوي التعبيرات للأنواع على بناء جملة خاص يختلف عن بناء جملة التعبيرات العادية. ربما لاحظت العديد من الأمثلة على بناء الجملة هذا أثناء العمل مع FSI (FSharp Interactive) ، كما يتم عرض أنواع كل تعبير إلى جانب نتائج تنفيذه.
كما تعلمون ، يستخدم F # خوارزمية استنتاج الكتابة ، لذلك لا تحتاج في كثير من الأحيان إلى كتابة أنواع في التعليمات البرمجية بشكل صريح ، لا سيما في الوظائف. ولكن للعمل بفعالية مع F # ، تحتاج إلى فهم بناء جملة الأنواع حتى تتمكن من تحديد أنواعك الخاصة ، وأخطاء تحويل نوع التصحيح ، وقراءة تواقيع الوظيفة. في هذه المقالة ، سأركز على استخدام الأنواع في تواقيع الوظائف.
فيما يلي بعض الأمثلة لتوقيعات بناء الجملة:
// // let add1 x = x + 1 // int -> int let add xy = x + y // int -> int -> int let print x = printf "%A" x // 'a -> unit System.Console.ReadLine // unit -> string List.sum // 'a list -> 'a List.filter // ('a -> bool) -> 'a list -> 'a list List.map // ('a -> 'b) -> 'a list -> 'b list
فهم وظائف من خلال التوقيعات
في كثير من الأحيان ، حتى من خلال دراسة توقيع دالة ما ، يمكنك الحصول على فكرة عما تفعله. النظر في بعض الأمثلة وتحليلها في المقابل.
int -> int -> int
هذه الوظيفة تأخذ معلمتين int
وتُرجع int
أخرى. على الأرجح ، هو نوع من الوظائف الرياضية ، مثل الجمع والطرح والضرب أو الأس.
int -> unit
تأخذ هذه الوظيفة وحدة int
، مما يعني أن الوظيفة تقوم بعمل مهم كتأثير جانبي. بسبب لا يُرجع قيمة مفيدة ، حيث ينتج عن التأثير الجانبي على الأرجح عمليات كتابة في IO ، مثل التسجيل أو الكتابة إلى قاعدة البيانات أو شيء مشابه.
unit -> string
لا تقبل هذه الوظيفة أي شيء ، ولكنها تُرجع string
، مما قد يعني أن الوظيفة تتلقى سلسلة من الهواء. نظرًا لعدم وجود إدخال صريح ، من المحتمل أن تقوم الوظيفة بشيء من خلال القراءة (قل من ملف) أو إنشاء (مثل سلسلة عشوائية).
int -> (unit -> string)
تأخذ هذه الدالة int
وتُرجع دالة أخرى تُرجع سلسلة عند استدعائها. مرة أخرى ، على الأرجح ، تؤدي الوظيفة عملية قراءة أو توليد. المدخلات من المحتمل أن تهيئ بطريقة ما وظيفة الإرجاع. على سبيل المثال ، قد يكون الإدخال هو معرف الملف ، وتكون الوظيفة التي تم إرجاعها مشابهة لـ readline()
. أو ، قد تكون المدخلات هي قيمة البدء لمولد سلسلة عشوائي. لا يمكننا القول بالتأكيد ، لكن يمكننا استخلاص بعض الاستنتاجات.
'a list -> 'a
تقبل الدالة قائمة من أي نوع ، ولكنها تُرجع قيمة واحدة فقط من هذا النوع. قد يشير هذا إلى أن الوظيفة تقوم بتجميع القائمة أو تحديد أحد عناصرها. توقيع مماثل هو List.sum
، List.max
، List.head
، إلخ.
('a -> bool) -> 'a list -> 'a list
تأخذ هذه الوظيفة معلمتين: الأولى هي وظيفة تحول شيئًا ما إلى bool
(المسند) ، والثانية هي قائمة. قيمة الإرجاع هي قائمة من نفس النوع. تستخدم المسندات لتحديد ما إذا كان كائن ما يفي بمعيار معين ، وما إذا كانت هذه الوظيفة يبدو أنها تحدد عناصر من قائمة وفقًا لمصطلح - صحيح أم خطأ. بعد ذلك ، تقوم بإرجاع مجموعة فرعية من القائمة الأصلية. مثال دالة مع هذا التوقيع هو List.filter
.
('a -> 'b) -> 'a list -> 'b list
تأخذ الوظيفة معلمتين: التحويل من النوع 'a
إلى النوع 'b
و قائمة النوع 'a
. قيمة الإرجاع هي قائمة من النوع 'b
. من المنطقي افتراض أن الوظيفة تأخذ كل عنصر من القائمة 'a
، وتحولها إلى 'b
، باستخدام الدالة التي تم تمريرها كمعلمة أولى ، ثم تُرجع القائمة 'b
. في الواقع ، List.map
هو النموذج الأولي لوظيفة مع مثل هذا التوقيع.
البحث عن أساليب المكتبة مع التوقيعات
التواقيع الوظيفية مهمة جدًا في العثور على وظائف المكتبة. تحتوي مكتبات F # على مئات الوظائف ، والتي يمكن أن تكون مربكة في البداية. على عكس اللغات الموجهة للكائنات ، لا يمكنك ببساطة "إدخال كائن" من خلال نقطة للعثور على جميع الأساليب ذات الصلة. ولكن إذا كنت تعرف توقيع الوظيفة المطلوبة ، يمكنك تضييق نطاق البحث بسرعة.
على سبيل المثال ، لديك قائمتان ، وتريد إيجاد وظيفة تجمع بينهما في قائمة. ما هو التوقيع الذي تريده الوظيفة؟ سيتطلب الأمر أخذ قائمتين كمعلمات وإرجاع ثالث ، كلهما من نفس النوع:
'a list -> 'a list -> 'a list
انتقل الآن إلى موقع وثائق MSDN لوحدة القائمة ، وابحث عن وظيفة مماثلة. اتضح أن هناك وظيفة واحدة فقط مع هذا التوقيع:
append : 'T list -> 'T list -> 'T list
ما تحتاجه!
تحديد الأنواع الأصلية للتوقيعات الوظيفية
يوما ما سوف ترغب في تحديد أنواع خاصة بك للوظيفة المطلوبة. يمكن القيام بذلك باستخدام الكلمة الأساسية "النوع":
type Adder = int -> int type AdderGenerator = int -> Adder
في المستقبل ، يمكنك استخدام هذه الأنواع لتقييد قيم معلمات الوظيفة.
على سبيل المثال ، سوف يقع إعلان ثان بسبب تقييد مع خطأ يلقي. إذا أزلناه (كما في الإعلان الثالث) ، فسيختفي الخطأ.
let a:AdderGenerator = fun x -> (fun y -> x + y) let b:AdderGenerator = fun (x:float) -> (fun y -> x + y) let c = fun (x:float) -> (fun y -> x + y)
اختبار فهم وظيفة التوقيعات
هل تفهم تواقيع الوظيفة جيدًا؟ تحقق من نفسك إذا كنت تستطيع إنشاء وظائف بسيطة باستخدام التواقيع أدناه. تجنب تحديد أنواع صراحة!
val testA = int -> int val testB = int -> int -> int val testC = int -> (int -> int) val testD = (int -> int) -> int val testE = int -> int -> int -> int val testF = (int -> int) -> (int -> int) val testG = int -> (int -> int) -> int val testH = (int -> int -> int) -> int
موارد إضافية
هناك العديد من البرامج التعليمية لـ F # ، بما في ذلك المواد لأولئك الذين يأتون مع تجربة C # أو Java. قد تكون الروابط التالية مفيدة كلما تعمقت في F #:
موصوفة أيضًا عدة طرق أخرى لبدء التعلم F # .
أخيرًا ، يعتبر مجتمع F # صديقًا للمبتدئين جدًا. هناك دردشة نشطة للغاية في Slack ، بدعم من F # Software Foundation ، مع غرف مبتدئين يمكنك الانضمام إليها بحرية . نحن نوصي بشدة أن تفعل هذا!
لا تنسَ زيارة موقع مجتمع الناطقين بالروسية F # ! إذا كانت لديك أي أسئلة حول تعلم اللغة ، فسيسعدنا مناقشتها في غرف الدردشة:
حول مؤلفي الترجمة
ترجم بواسطة kleidemos
تم إجراء تغييرات في التحرير والتحرير من خلال جهود مجتمع الناطقين باللغة الروسية من مطوري F # . نشكر أيضًا @ schvepsss و @ shwars على إعداد هذه المقالة للنشر.