فهم خطأ نوع: "من المتوقع توقيع كثافة العمليات * Int-> كثافة العمليات إلا أن كثافة العمليات * Int-> كثافة العمليات"

StackOverflow https://stackoverflow.com/questions/324612

  •  11-07-2019
  •  | 
  •  

سؤال

والتعليقات على ستيف ييغج الصورة <لأ href = "HTTP: // steve- yegge.blogspot.com/2008/06/rhinos-and-tigers.html "يختلط =" نوفولو noreferrer "> آخر عن <لأ href =" http://www.mozilla.org/rhino/ "يختلط = "نوفولو noreferrer"> من جانب الخادم جافا سكريبت التي مناقشة مزايا أنظمة نوع في لغات وهذا <وأ href = "http://steve-yegge.blogspot.com/2008/06/rhinos-and- ؟ tigers.html showComment = 1213654200000 # c869153593831177660 "يختلط =" نوفولو noreferrer "> تعليق يصف:

<اقتباس فقرة>   

... أمثلة من HM أنظمة نمط حيث يمكنك الحصول على أشياء مثل:

expected signature Int*Int->Int but got Int*Int->Int

ويمكنك ان تعطي مثالا على تعريف وظيفة (أو اثنين؟) واستدعاء دالة التي من شأنها أن تنتج هذا الخطأ؟ الذي يبدو أنه قد يكون من الصعب جدا لتصحيح في برنامج واسع العش.

وبالإضافة إلى ذلك، قد رأيته في خطأ مماثل في ميراندا ؟ (أنا لم تستخدم منذ 15 عاما وحتى ذاكرتي من هو غامض)

هل كانت مفيدة؟

المحلول

وكنت تأخذ (وعلا بيني و) الآراء Yegge على الكتابة ثابتة مع حبة الملح. إذا كنت أقدر ما يعطي الكتابة ثابتة لك، وستعرف كيف يمكن لنظام نوع من لغة البرمجة اخترت الأشغال.

وIIRC، يستخدم ML بناء الجملة '* لالصفوف. <نوع> * <نوع> هو نوع الصفوف (tuple) مع اثنين من العناصر. لذا، فإن (1، 2) لديها كثافة اكتب * كثافة العمليات.

وكلا هاسكل واستخدام ML -> عن وظائف. في ML، كثافة * كثافة العمليات -> كثافة العمليات سيكون نوع من دالة التي تأخذ الصفوف (tuple) من int و int و خرائط لعدد صحيح

.

واحدة من الأسباب التي قد ترى خطأ أن تبدو غامضة مثل واحد نقلت علا عندما يأتي إلى ML من لغة مختلفة، وإذا حاولت وتمرير الوسائط استخدام الأقواس والفواصل، وكأنه واحد من شأنه في C أو باسكال، ل دالة التي تأخذ معلمتين.

والمشكلة هي، اللغات الوظيفية عموما وظائف نموذج من أكثر من معلمة وظائف تعود وظائف. جميع وظائف يستغرق سوى حجة واحدة. إذا كانت وظيفة يجب أن يأخذ حجتين، بدلا من ذلك يأخذ حجة وإرجاع وظيفة من حجة واحدة، والتي ترجع النتيجة النهائية، وهلم جرا. لجعل ويتم كل هذا، وتطبيق وظيفة مقروءا ببساطة عن طريق جنبا إلى جنب (أي وضع التعبيرات بجانب بعضها البعض).

وهكذا، وظيفة بسيطة في ML (ملاحظة: أنا باستخدام F # كما بلدي ML) قد تبدو قليلا مثل:

let f x y = x + y;;

وله اكتب:

val f : int -> int -> int

و(A ظيفة اتخاذ عدد صحيح وإعادة وظيفة التي تأخذ نفسها عدد صحيح وتقوم بإرجاع عدد صحيح).

ولكن، إذا كنت استدعاء بسذاجة أنه مع الصفوف (tuple):

f(1, 2)

... ستحصل على خطأ، لأنك مررت كثافة * كثافة العمليات إلى شيء تتوقع عدد صحيح.

وأتوقع أن هذا هو "مشكلة" وعلا يحاول أن يطعن في. أنا لا أعتقد أن المشكلة هي سيئة كما كان يعتقد، على الرغم؛ بالتأكيد، انها أسوأ بكثير في قوالب C ++.

نصائح أخرى

ومن الممكن أن هذا كان في إشارة إلى مترجم مكتوبة بشكل سيئ والتي فشلت في إدراج الأقواس لإزالة الغموض رسائل الخطأ. على وجه التحديد، توقعت وظيفة في الصفوف (tuple) من int وعادت لint، ولكن يمكنك تمرير الصفوف (tuple) من int وظيفة من int إلى int. بشكل أكثر تحديدا (في ML):

fun f g = g (1, 2);

f (42, fn x => x * 2)

وهذا سوف ينتج الخطأ من النوع مشابهة لما يلي:

<اقتباس فقرة>   

والمتوقعة نوع int * int -> int، وحصلت على نوع int * (int -> int)

إذا حذفت الأقواس، يمكن أن يكون هذا الخطأ غامضة بشكل مزعج.

ومن الجدير بالذكر أن هذه المشكلة هي أبعد ما تكون عن كونها محددة لهيندلي-ميلنر. في الواقع، لا أستطيع التفكير في أي نوع غريب <م> أخطاء التي هي محددة لH-M. على الأقل، لا شيء مثل المثال معين. وأظن أن علا كان مجرد تهب الدخان.

وبما أن العديد من لغة وظيفية تسمح لك rebind أسماء الأنواع في نفس الطريقة يمكنك rebind المتغيرات، هو في الواقع من السهل جدا أن ينتهي مع وجود خطأ مثل هذا، خاصة إذا كنت تستخدم أسماء عامة إلى حد ما لأنواع بك (على سبيل المثال، t) في وحدات مختلفة. وهنا مثال بسيط في لغة كامل الموضوعية:

# let f x = x + 1;;
val f : int -> int = <fun>
# type int = Foo of string;;
type int = Foo of string
# f (Foo "hello");;
This expression has type int but is here used with type int

وماذا فعلت هنا هو rebind في int نوع معرف إلى نوع جديد غير متوافق مع المدمج في نوع int. مع أكثر قليلا جهد، يمكننا الحصول على المزيد أو أقل نفس الخطأ على النحو الوارد أعلاه:

# let f g x y = g(x,y) + x + y;;
val f : (int * int -> int) -> int -> int -> int = <fun>
# type int = Foo of int;;
type int = Foo of int
# let h (Foo a, Foo b) = (Foo a);;
val h : int * int -> int = <fun>
# f h;;
This expression has type int * int -> int but is here used with type
  int * int -> int
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top