功能[与通用数据类型]?在斯卡拉。我怎么做到这一点?

时间:2013-10-25 18:09:00

标签: scala type-systems

我正在尝试选择一些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并抛出此异常。难道我完全错误地使用了这种结构吗?

THX

3 个答案:

答案 0 :(得分:1)

问题是您为泛型类型A调用+。编译器尝试推断使用+的内容(如String),并且您得到错误。我也不了解你想用+。

实现的目标

答案 1 :(得分:1)

您不能保证方法+可用于A类型。因此,编译器将A转换为String

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

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

recFunc[A:Addable]…

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

答案 2 :(得分:1)

您在+上调用了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)

有许多方法可以改进这一点,例如使用隐式类和上下文边界。有关implicits和上下文边界的更多信息,请参阅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,尽管它的示例非常低。