【问题标题】:Scala: Type Error When Enriching CollectionsScala:丰富集合时的类型错误
【发布时间】:2014-03-22 16:31:45
【问题描述】:

所以我正在尝试通过 Norvig & Russell 的“人工智能,一种现代方法”作为学习 Scala 的一种方式。在这一点上,我已经很好地掌握了语言基础知识,但我仍然发现自己经常与类型系统“战斗”。

长话短说,广度优先和深度优先搜索算法除了推送/弹出到其底层集合的机制外是相同的。深度优先将追加新的可能性并使用堆栈,而广度优先将追加并使用队列。

为了保持我的算法不变,我创建了一个名为“GiveGrab”(我知道,可怕的名字)的类型类,目的是用这些“默认" push (give) 和 pop-like (grab) 操作。例如,grab 会导致调用 .dequeue() 用于队列,调用 .pop() 用于堆栈。

以下是代码(略为缩写):

object Example extends App {

  trait GiveGrab[A, M[A]] {
    def give(x: A*): M[A]
    def grab(): A
  }

  implicit class GiveGrabQueue[T](q: Queue[T]) extends GiveGrab[T,Queue[T]] {
    override def give(x: T*) = q ++= x
    override def grab() = q.dequeue()
  }

  class TestClass[T, X <% GiveGrab[T, Queue[T]]](var storage: X) {}

  val test = new TestClass[Int, Queue[Int]](new Queue[Int]())

}

在尝试编译时,我收到以下错误:

Error:(18, 39) scala.collection.mutable.Queue[T] takes no type parameters, expected: one
  class TestClass[T, X <% GiveGrab[T, Queue[T]]](var storage: X) {}
                                  ^
Error:(13, 67) scala.collection.mutable.Queue[T] takes no type parameters, expected: one
  implicit class GiveGrabQueue[T](q: Queue[T]) extends GiveGrab[T,Queue[T]] {
                                                              ^

也就是说,我经过大量的反复试验才达到这一点。我不确定我的特质是否真的应该被输入 trait GiveGrab[A, M[A]] 或者 trait GiveGrab[A, M[_]] 或者 trait GiveGrab[A, M]

错误“不接受类型参数,预期:一个”在这一点上对我来说没有多大意义,而且关于该消息的其他帖子很少(一些与依赖类型相关,还有一些与 Play 框架相关)。

有点相关:有没有了解 Scala 类型签名的好文章?我通读了 Programming in Scala 2nd Ed,但它并没有真正涉及到这种类型的体操(或者我只是错过了它。)

编辑:错别字

【问题讨论】:

  • 如果您将定义更改为extends GiveGrab[T, Queue]class TestClass[T, X &lt;% GiveGrab[T, Queue]],它将正常工作。我不完全确定为什么这种表示法有效(可能是因为M[_] 符合已经参数化的类型Queue[T]),因此它只是一个评论而不是答案,但有人对更高的知识有更多的了解Scala 中的 -kinded 类型可能会在这里有所启发。
  • 刚刚测试过——正如你所说——它似乎工作正常。至少在我们等待有人解释原因时,我有一个解决方法。 :) 谢谢帕特里克!

标签: scala implicit-conversion scala-collections


【解决方案1】:

@PatrykĆwiek 提出的不是一种解决方法,而是您真正应该做的事情:M[A] 在 trait GiveGrab 中定义了一个类型函数。粗略地说,这意味着:M 是一种类型,您可以在其中应用单个类型参数来生成具体类型。该参数称为A 纯属巧合。以下意思相同:

trait GiveGrab[A,M[MyRandomName]] { ... }

give 的定义中,当说M[A] 时,你实际上是使用这个类型函数来创建一个类型。因此,正如@PatrykĆwiek 所说,您应该写Queue 而不是Queue[T]。虽然Queue 正是这些类型函数之一,但Queue[T] 是一个具体类型,因此不适用于M 的定义。

您收到的错误消息确切地说:在M 的位置,您应该放置一个带参数的类型(如Queue),但您放置了一个不带参数的类型(Queue[T]在您的情况下,另一个示例是 StringInt)。

【讨论】:

  • 谢谢,这个解释很有道理。我认为我没有正确“解析”错误消息也没有帮助。
猜你喜欢
  • 2011-10-12
  • 1970-01-01
  • 2011-07-21
  • 2014-01-11
  • 2019-03-04
  • 1970-01-01
  • 2023-03-06
  • 2012-05-25
相关资源
最近更新 更多