使用Implicits将类型参数视为数字

时间:2015-05-20 17:27:09

标签: scala

我在使用以下多态函数定义时遇到了问题:

scala> def foo[A](x : A, y : A)(implicit o : A => Numeric[A]) : A = x + y
<console>:7: error: type mismatch;
 found   : A
 required: String
       def foo[A](x : A, y : A)(implicit o : A => Numeric[A]) : A = x + y

我想指定类型参数A可以用作Numeric,但它不起作用。我做错了什么?

2 个答案:

答案 0 :(得分:4)

Numeric[A]通常是单个实例,可以访问类型A上的算术运算。它将包含def plus(x: A, y: A): A,而不是def add(x: A): A,其中包含this类型的Comparator

类似于java的Ordering(或scala的Compare(T o1, T o2)),它有Comparable,而不是java Ordered(scala的CompareTo(T other))一个A。在Haskell语言中密切相关的特征之后,具有隐式可用的单例实现的这种类型通常被称为类型类。

因此,您不希望将Numeric[A]转换为Numeric[A],只需要def foo[A](x: A, y: A)(implicit numeric: Numeric[A]) 。 你的签名应该是

def foo[A: Numeric](x: A, y: A)

有一个快捷方式,即

foo

在方法numeric.plus(x,y)中,您可以执行import scala.math.Numeric._,但如果您x + y,则会获得一些魔力,而且更方便[A: Numeric]

关于评论中的问题:自scala编程以来是否有语言更改(第2.8版)?

语法context bound,称为implicit Numeric[A],已在语言后期引入,我不是百分百肯定,但我相信它在2.8中不可用。但这只是Numeric参数的快捷方式,这可能是2.8(Comparable可用 - 实际上只是在2.8中引入),并且应该如上所示使用。除此之外,没有语言变化。

然而,在scala的早期,使用“views”更常见,这意味着隐式转换,而不是类型,即使用Ordered / Comparator等类型比Ordering / Numeric / A <: Ordered[A]

对于此类型,通常使用上限Ordered。但是,这可能有点过于严格,因为只有实现者有远见才能实现A时它才会起作用。你可以解决这个问题,但要求implicit A => Ordered[A]可以转换为有序[A],所以[A <% Ordered[A]]

曾经有一个快捷方式,implicit A => Ordered[A],称为视图绑定。但是,它已被弃用,虽然仍然可以查看视图(Numeric[A]),但更喜欢类型类。这有很多原因,例如:

  • 在隐式范围内拥有转换函数将充当隐式转换并且非常危险
  • 类型类更强大。例如,即使您没有A的实例,也可以拥有zero的实例,因此请获取A类型的sum。如果您在列表中拨打Numeric并且列表为空,则zero仍然可用,您可以获得Numeric。如果Azero实现,即使它jArrayFull可用,您也没有实例可以调用它。另一个例子,类型类可以用作工厂,再次当你没有构造类型的实例时(如)this answer中所示。

引用Martin Odersky(discussing deprecation):

  

上下文边界本质上是视图边界的替代。它的   从一开始我们应该做些什么,但我们不知道更好   那时候

答案 1 :(得分:2)

您需要做的两项更改是,首先 implicit不应该是ANumeric[A]的功能,而只是Numeric[A] second ,您需要导入Numeric.Implicits以获取启用Ops的隐式+

import scala.math.Numeric.Implicits._

def foo[A](x : A, y : A)(implicit num: Numeric[A]) : A = x + y

如果没有导入,您必须将其写为:

def foo[A](x : A, y : A)(implicit num: Numeric[A]) : A = num.plus(x,y)