1

我正在尝试选择一些 Scala,并且在有趣的功能中我发现了具有通用(输入类型)的函数?特别有用。但是尝试以下代码,

def recFunc[A](xs: List[A], base : () => A) : A = if (xs.isEmpty) base() else xs.head + recFunc(xs.tail, base)

我得到下面写的烦人的错误:

<console>:8: error: type mismatch;
 found   : List[A]
 required: List[String]
   def recFunc[A](xs: List[A], base : () => A) : A = if (xs.isEmpty) base() else xs.head + recFunc(xs.tail.asInstanceOf[List[A]], base)

到底,类型推断系统是如何提出 A == String 并抛出此异常的。难道是我完全错误地使用了这种结构吗?

谢谢

4

3 回答 3

1

您正在调用+on 方法A,但不能保证A有这样的方法。有两种方法可以解决这个问题:继承或类型类。

使用继承,找到所有所需类的共同祖先(包括您想要的方法)将是一件简单的事情,然后您将编写[A <: CommonAncestor]. 不幸的是,由于努力使 Scala 与 Java 和一般 JVM 限制互操作,数字原语没有这样的祖先。

那么,我们就剩下类型类了。“类型类”这个表述来自 Haskell,其思想是可以将不同的类型分组到一个类中,这些类具有一些共同的属性。它与继承之间的主要区别在于类型类对扩展是开放的:您可以轻松地将任何类型添加到这样的类中。

Scala 没有直接类型类支持。相反,我们使用“类型类模式”来模拟它。基本上,我们创建了一个类——类型类——它包含我们想要的方法。接下来,我们为我们希望支持的每种类型创建该类的实例。最后,我们隐式传递这些实例,这使得编译器的工作是找到所需的实例。

在您的示例中,我们可以这样做:

// Our type class
class Addable[T] {
  def plus(a: T, b: T): T
}

// Or Int instance
object AddableInt {
  class AddableInt extends Addable[Int] {
    def plus(a: Int, b: Int): Int = a + b
  }
  implicit val addableInt = new AddableInt
}

// Make the implicit available
import AddableInt._

// Make recFunc use it
def recFunc[A](xs: List[A], base : () => A)(implicit addable: Addable[A]): A = 
  if (xs.isEmpty) base() else addable.plus(xs.head, recFunc(xs.tail, base))

// call recFunc
recFunc(List(1, 2, 3), () => 0)

有很多方法可以改善这一点,例如使用隐式类和上下文边界。请参阅 Stack Overflow 上的Scala wiki,了解有关隐式和上下文边界的更多信息(分别为第 23 和第 19 节)。

现在,Scala 已经有了基本算术的上下文边界,甚至还有一些使用视图边界的额外技巧来使其无缝使用。以下是如何使其仅与标准库一起使用:

import scala.math.Numeric.Implicits._
def recFunc[A : Numeric](xs: List[A], base : ()=>A) : A = 
    if (xs.isEmpty) base() else xs.head + recFunc(xs.tail, base)

另请参阅Numeric scaladoc,尽管它的示例非常少。

于 2013-10-25T19:40:54.903 回答
1

您不保证该方法+可用于 type A。因此,编译器转换AString.

一种解决方案包括使用类型类。

trait Addable[A] {
    def plus(x: A, y: A): A
}

recFunc[A:Addable]…

您可以在这里查看 spire,简短介绍:http: //typelevel.org/blog/2013/07/07/generic-numeric-programming.html

于 2013-10-25T18:37:34.747 回答
1

问题是您为泛型类型 A 调用 +。编译器尝试推断使用 + 的内容(如 String),但您会收到错误消息。我也不明白你想用 + 实现什么。

于 2013-10-25T18:15:00.350 回答