【问题标题】:How to set type parameter bound in scala to make generic function for numerics?如何在 scala 中设置类型参数绑定以生成数字的通用函数?
【发布时间】:2014-02-13 16:40:16
【问题描述】:

我想制作一个适用于所有数值类型的 sum 函数。

这行得通:

object session {
  def mapReduce[A](f: A => A, combine: (A, A) => A, zero: A, inc: A)
                  (a: A,b: A)
                  (implicit num:Numeric[A]): A = {
    def loop(acc: A, a: A) =
    if (num.gt(a, b)) acc
    else combine(f(a), mapReduce(f, combine, zero, inc)(num.plus(a, inc), b))
    loop(zero, a)
  }

  def sum(f: Int => Int)
         (a: Int, b: Int) : Int = {
    mapReduce(f, (x: Int, y: Int) => x + y, 0, 1)(a, b)}
  sum(x => x)(3, 4)  //> res0: Int = 7

  def product(f: Int => Int)
             (a: Int, b: Int): Int = {
    mapReduce(f, (x: Int, y: Int) => x * y, 1, 1)(a, b)}
  product(x => x)(3, 4) //> res1: Int = 12

  def fact(n: Int) = product(x => x)(1, n)
  fact(5) //> res3: Int = 120
}

但是当我尝试像这样使 sum 通用时:

def sum[A](f: A => A)
           (a: A, b: A)
           (implicit num:Numeric[A]): A = {
  mapReduce(f, (x: A, y: A) => num.plus(x, y), 0, 1)(a, b)}
sum(x => x)(3.0, 4.0) // should be 12.0

我在 f 上收到此错误

类型不匹配;找到:A => A 必需:Any => Any

当我将它传递给 mapReduce 时。那么我需要做什么才能使 sum 接受任何数值?

【问题讨论】:

    标签: scala generics types implicit


    【解决方案1】:

    如果我没记错的话,除了调用mapReduce而不是调用sum时必须明确类型之外,其他答案几乎是正确的。

    因此,在您对sum 的通用定义中,您可能希望这样做:

    def sum[A](f: A => A)(a: A, b: A)(implicit num: Numeric[A]): A =
      mapReduce[A](f, num.plus, num.zero, num.one)(a, b)
    

    然而,这还不足以让打字员推断出A 的具体类型,例如Double 拨打sum(x => x)(3.0, 4.0) 时。原因是类型器从第一个参数列表到最后一个参数列表,从左到右。 您的第一个参数列表声明了f: A => A,只有第二个参数列表定义了(a: A, b: A)。一旦类型器到达第一个参数列表的末尾,它就不知道A 到底是什么,因此它将A 的类型固定为一些“抽象”A。在这一点上,它唯一知道A 的是它是Any 的子类型。 当打字机然后进入第二个参数列表时,理论上它可以将A 推断为Double 或任何您的具体类型,但如前所述,类型已经被修复。这只是 Scala 打字机的一个缺陷,一旦你掌握了它,就可以很容易地绕过它。 更准确地说,您所要做的就是通过像这样切换第一个和第二个参数列表来帮助打字员:

    def sum[A](a: A, b: A)(f: A => A)(implicit num: Numeric[A]): A =
      mapReduce[A](f, num.plus, num.zero, num.one)(a, b)
    

    然后可以调用sum 而无需明确说明类型,例如

    Console println sum(3.0, 4.0)(x => x)     // 7.0
    

    【讨论】:

    • 这是 scala 打字机的 bug 还是设计缺陷?
    • 这是一个功能 ;-) 这个问题已经存在了很长时间,我认为它也会存在。我不确定使用的是哪种类型推断算法,但绝对不是 Hindley-Milner。从here 开始可能还有更多信息。
    【解决方案2】:

    明确给出sum 的类型。我已经在

    中提供了类似问题的答案

    A simple foldRight type issue in Scala.

    问题完全不同,但原因完全一样。

    【讨论】:

    • stackoverflow.com/questions/how-to-answer 请回答而不是发布链接
    • 我该怎么做?这应该有什么帮助?我想 sum 从它得到的值中推断出类型。
    • 查看@tiran 链接到的答案。这是 scala typer 从左到右的问题,并且(一般来说)推断你的 A 有点太早了(从第一个参数列表中)。调用 sum[Double]sum[Int],即在调用站点上明确显示类型,这应该可以解决问题。
    • 当我这样做 sum[Double](x => x)(3.0, 4.0)sum[Int](x => x)(3, 4) 时出现同样的错误
    • 对不起,我的错误。而是在调用mapReduce 时明确类型,例如:def sum[A](f: A => A)(a: A, b: A)(implicit num: Numeric[A]): A = mapReduce[A](f, num.plus, num.zero, num.one)(a, b)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-02
    • 2010-11-18
    • 1970-01-01
    • 2011-11-05
    • 1970-01-01
    • 2015-02-22
    相关资源
    最近更新 更多