需要帮助找出 Scala 编译器错误

发布于 2024-09-02 02:16:20 字数 911 浏览 8 评论 0原文

我一直在用 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)))

给出以下错误:
类型不匹配;
发现:(点,点)=>国际
必填:(任意,点)=> Any

我对这两个错误消息感到非常困惑。如果有人能更清楚地解释我做错了什么,我将非常感激。是的,我看到第二个错误说我需要输入“Any” ”但我不明白如何实施一个可以根据需要进行的更改。显然,简单地将“a:Point”更改为“a:Any”并不是一个可行的解决方案,那么我错过了什么?

I have been working on a project in scala, but I am getting some error messages that I don't quite understand. The classes that I am working with are relatively simple.
For example:

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

Now suppose that I create a Polygon:

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

Then if I attempt to determine the location and size of the smallest possible rectangle that could contain the polygon, I get various errors that I don't quite understand.

Below are snippets of different attempts and the corresponding error messages that they produce.

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

Gives the error:
"missing parameter type for expanded function ((x$1) => x$1.x)"

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

Gives this error:
"type mismatch;
found : (Point, Point) => Int
required: (Any, Point) => Any
"

I am very confused about both of these error messages. If anyone could explain more clearly what I am doing incorrectly, I would really appreciate it. Yes, I see that the second error says that I need type "Any" but I don't understand exactly how to implement a change that would work as I need it. Obviously simply changing "a: Point" to "a: Any" is not a viable solution, so what am I missing?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

策马西风 2024-09-09 02:16:20

reduceLeft 的类型为 reduceLeft[B >: A](op: (B, A) => B): B, APoint,并且您尝试将其应用于 (a: Point, b: Point) =>; (Math.min(ax,bx))

编译器的推理如下:Math.min(ax, bx) 返回 Int,因此 Int 必须是 B 的子类型代码>.并且 B 也必须是 Point 的超类型。为什么? B 是累加器的类型,其初始值是 Polygon 中的第一个 Point。这就是B>:A的含义。

IntPoint 的唯一超类型是 Any;所以 BAny 并且 op 的类型应该是 (Any, Point) =>;任何,正如错误消息所示。

The type of reduceLeft is reduceLeft[B >: A](op: (B, A) => B): B, A is Point, and you are trying to apply it to (a: Point, b: Point) => (Math.min(a.x, b.x)).

The compiler reasons thus: Math.min(a.x, b.x) returns Int, so Int must be a subtype of B. And B must also be a supertype of Point. Why? B is the type of the accumulator, and its initial value is the first Point in your Polygon. That's the meaning of B >: A.

The only supertype of Int and Point is Any; so B is Any and the type of op should be (Any, Point) => Any, just as the error message says.

南七夏 2024-09-09 02:16:20

这是 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) => 类型的函数点。 (更准确地说,(B, Point) => B,其中 B 的下界为 Point。请参阅 Scaladoc 方法 减少左

This is 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 requires here a function of the type (Point, Point) => Point. (more precisely (B, Point) => B with B with a lower bound to Point. See Scaladoc at the method reduceLeft.

同展鸳鸯锦 2024-09-09 02:16:20

另一种选择是poly.points.foldLeft(Int.MaxValue)((b, a) => Math.min(b, ax)),它也应该适用于 Scala 2.7.x。与reduceLeft版本相比,不同之处在于

  • 您有一个起始值(在我们的例子中,任何实际数据都会小于或等于该值),
  • 元素的类型和结果的类型,例如reduceLeft的下界约束
    不过Eastsun的解决方案更加优雅。

顺便说一句,如果您已经有了案例类,您可以省略 new 关键字,并且可以在伴随对象中使用自动生成的工厂方法。因此,创建多边形的线变为 val poly = Polygon(Point(2,5), Point(7,0), Point(3,1)),这更容易阅读。

Another alternative is poly.points.foldLeft(Int.MaxValue)((b, a) => Math.min(b, a.x)), which should also work with Scala 2.7.x. The differences compared to the reduceLeft version are

  • you have a start value (Int.MaxValue in our case, any real data will be smaller or equal to this)
  • there are no constraints between the type of the elements and the type of the result, like the lower bound constraint for reduceLeft
    Nevertheless Eastsun's solution is more elegant.

BTW if you already have case classes you can ommit the new keyword, and can use the automatically generated factory method in the companion object. So the line creating the poly becomes val poly = Polygon(Point(2,5), Point(7,0), Point(3,1)), which is a bit easier to read.

薆情海 2024-09-09 02:16:20

我看到每个人似乎都已经锁定了第二个片段,所以我将回答第一个片段:

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 。如果下划线出现在任何类型的表达式中,例如示例中的方法调用,则该下划线是匿名函数中参数的占位符。

在第二个含义中,理解匿名函数的边界尤为重要。具体来说,匿名函数将由最里面的括号或括起来的大括号或任何逗号分隔。

现在,将该规则应用于第一个片段中的表达式意味着编译器会像这样看到 snipper:

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

因此,这里有两个问题。首先,您将两个函数传递给 min,而不是两个双精度数。其次,由于 min 并不期望接收函数,因此编译器无法推断这些函数的类型。由于您没有提供有关上面 ab 类型的任何信息,因此它会对此进行抱怨。

如果您确实提供了此类类型,则错误消息将如下所示:

<console>:6: error: type mismatch;
 found   : Int
 required: ?{val x: ?}

I see everyone seems to have latched onto the second snippet, so I'll answer the first one:

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

You intended that to mean this:

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

However, that's not how underscore works. There are many meanings to underscore, but two of them are relevant here.

First, it may mean a partial function application. For example, Math.min(_, 0) would partially apply the parameters to min, and return a function that apply the remaining ones. In other words, it is equivalent to x => Math.min(x, 0), ignoring the type annotations. At any rate, this meaning only applies if the underscore is all by itself in the place of one (or more) of the parameters.

That, however, is not the case in your example, because you added a .x after the underscore. If the underscore appears in any kind of expression, such as the method call in your example, then that underscore is a placeholder for a parameter in an anonymous function.

In this second meaning it is particularly important to understand the boundaries of the anonymous function. Specifically, the anonymous function will be delimited by the innermost parenthesis or curly brackets that encloses it, or by any comma.

Now, applying that rule to the expression in the first snippet means that snipper is seen by the compiler like this:

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

So, there are two problems here. First, you are passing two functions to min instead of two doubles. Second, because min isn't expecting to receive functions, the compiler can't infer what the type of these functions might be. Since you did not provide any information about the types of a and b above, it complains about that.

If you did provide such types, the error message would be something like this:

<console>:6: error: type mismatch;
 found   : Int
 required: ?{val x: ?}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文