بحاجة إلى مساعدة في اكتشاف أخطاء مترجم سكالا

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

  •  03-10-2019
  •  | 
  •  

سؤال

لقد كنت أعمل في مشروع في Scala ، لكنني أتلقى بعض رسائل الخطأ التي لا أفهمها تمامًا. الفصول الدراسية التي أعمل معها بسيطة نسبيا. فمثلا:

abstract class Shape
case class Point(x: Int, y: Int) extends Shape
case class Polygon(points: Point*) extends Shape

افترض الآن أنني أقوم بإنشاء مضلع:

val poly = new Polygon(new Point(2,5), new Point(7,0), new Point(3,1))

ثم إذا حاولت تحديد موقع وحجم أصغر مستطيل ممكن يمكن أن يحتوي على المضلع ، فأنا أحصل على أخطاء مختلفة لا أفهمها تمامًا.

فيما يلي مقتطفات من المحاولات المختلفة ورسائل الخطأ المقابلة التي تنتجها.

val upperLeftX = poly.points.reduceLeft(Math.min(_.x, _.x))

يعطي الخطأ:
"نوع المعلمة المفقودة للدالة الموسعة ((x $ 1) => x $ 1.x)"

val upperLeftX =  
         poly.points.reduceLeft((a: Point, b: Point) => (Math.min(a.x, b.x)))

يعطي هذا الخطأ:
"عدم تطابق نوع؛
وجدت: (نقطة ، نقطة) => int
مطلوب: (أي ، نقطة) => أي
"

أنا في حيرة من أمري بشأن كل من رسائل الخطأ هذه. إذا كان بإمكان أي شخص أن يشرح بشكل أكثر وضوحًا ما أقوم به بشكل غير صحيح ، فأنا أقدر ذلك حقًا. نعم ، أرى أن الخطأ الثاني يقول إنني بحاجة إلى نوع "أي" ، لكنني لا أفهم بالضبط كيفية تنفيذ التغيير الذي سيعمل كما أحتاج إليه. من الواضح ببساطة تغيير "A: Point" إلى "A: any" ليس حلًا قابلًا للتطبيق ، فما الذي أفتقده؟

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

المحلول

نوع من reduceLeft هو reduceLeft[B >: A](op: (B, A) => B): B, A هو Point, ، وأنت تحاول تطبيقه على (a: Point, b: Point) => (Math.min(a.x, b.x)).

أسباب المترجم هكذا: Math.min(a.x, b.x) عائدات Int, ، لذا Int يجب أن يكون نوعًا فرعيًا لـ B. و B يجب أن يكون أيضًا مجموعة رائعة من Point. لماذا ا؟ B هو نوع المجمع ، وقيمته الأولية هي الأولى Point في الخاص بك Polygon. هذا هو معنى B >: A.

الفائق الوحيد من Int و Point هو Any; ؛ لذا B هو Any ونوع op يجب ان يكون (Any, Point) => Any, ، كما تقول رسالة الخطأ.

نصائح أخرى

هذا هو Scala 2.8.0.rc2

scala> abstract class Shape
defined class Shape

scala> case class Point(x: Int, y: Int) extends Shape
defined class Point

scala> case class Polygon(points: Point*) extends Shape
defined class Polygon

scala> val poly = new Polygon(new Point(2,5), new Point(7,0), new Point(3,1))
poly: Polygon = Polygon(WrappedArray(Point(2,5), Point(7,0), Point(3,1)))

scala> val upperLeftX = poly.points.reduceLeft((a:Point,b:Point) => if (a.x < b.x) a else b)
upperLeftX: Point = Point(2,5)

reduceLeft يتطلب هنا وظيفة من النوع (Point, Point) => Point. (أكثر دقة (B, Point) => B مع B مع الحد الأدنى ل Point. نرى Scaladoc في هذه الطريقة reduceLeft.

بديل آخر هو poly.points.foldLeft(Int.MaxValue)((b, a) => Math.min(b, a.x)), ، والتي يجب أن تعمل أيضًا مع Scala 2.7.x. الاختلافات مقارنة بإصدار reduceleft

  • لديك قيمة بداية (Int.MaxValue في حالتنا ، ستكون أي بيانات حقيقية أصغر أو تساوي ذلك)
  • لا توجد قيود بين نوع العناصر ونوع النتيجة ، مثل القيد المرتبط السفلي لخفض حل Eastsun أكثر أناقة.

راجع للشغل إذا كان لديك بالفعل فئات حالات ، فيمكنك أن تميل إلى الكلمة الرئيسية الجديدة ، ويمكنك استخدام طريقة المصنع التي تم إنشاؤها تلقائيًا في الكائن المصاحب. لذلك يصبح الخط الذي ينشئ بولي val poly = Polygon(Point(2,5), Point(7,0), Point(3,1)), ، وهو أسهل قليلاً للقراءة.

أرى أن كل شخص يبدو أنه تم إغلاق المقتطف الثاني ، لذلك سأجيب على الأول:

val upperLeftX = poly.points.reduceLeft(Math.min(_.x, _.x))

كنت تنوي أن يعني هذا:

val upperLeftX = poly.points.reduceLeft((a, b) => Math.min(a.x, b.x))

ومع ذلك ، هذا ليس كيف يعمل السطحي. هناك العديد من المعاني للتطبيق ، لكن اثنان منهم وثيق الصلة هنا.

أولاً ، قد يعني تطبيق الوظيفة الجزئية. فمثلا، Math.min(_, 0) سيكون تنطبق جزئيا المعلمات ل min, ، وإرجاع وظيفة تطبق تلك المتبقية. بمعنى آخر ، يعادل x => Math.min(x, 0), ، تجاهل نوع التعليقات التوضيحية. على أي حال ، هذا المعنى فقط ينطبق إذا كان السفار السفلي هو نفسه في مكان واحد (أو أكثر) من المعلمات.

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

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

الآن ، فإن تطبيق هذه القاعدة على التعبير في المقتطف الأول يعني أن القنص ينظر إليه من قبل المترجم مثل هذا:

val upperLeftX = poly.points.reduceLeft(Math.min(a => a.x, b => b.x))

لذلك ، هناك مشكلتان هنا. أولاً ، أنت تمر وظيفتين min بدلا من اثنين من الزوجي. ثانياً ، لأن min لا يتوقع استلام الوظائف ، لا يمكن للمترجم أن يستنتج نوع هذه الوظائف. نظرًا لأنك لم تقدم أي معلومات حول أنواع a و b أعلاه ، يشكو من ذلك.

إذا قدمت مثل هذه الأنواع ، فستكون رسالة الخطأ شيئًا من هذا القبيل:

<console>:6: error: type mismatch;
 found   : Int
 required: ?{val x: ?}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top