以下多态方法编译:
import spire.math._
import spire.implicits._
scala> def foo[A:Numeric](d : A) = 2 * d
foo: [A](d: A)(implicit evidence$1: spire.math.Numeric[A])A
scala> def foo[A:Numeric](d : A) = 2 + d
foo: [A](d: A)(implicit evidence$1: spire.math.Numeric[A])A
但是,如果我将整数2
更改为double 2.0
,编译器会抱怨没有找到隐含值
scala> def foo[A:Numeric](d : A) = 2.0 + d
<console>:19: error: could not find implicit value for parameter ev: spire.algebra.Field[A]
def foo[A:Numeric](d : A) = 2.0 + d
^
scala> def foo[A:Numeric](d : A) = 2.0 * d
<console>:19: error: could not find implicit value for parameter ev: spire.algebra.Field[A]
def foo[A:Numeric](d : A) = 2.0 * d
^
我试图理解其他一些问题和答案,但我不知道如何解决这个问题。
答案 0 :(得分:2)
我发现使用reify
(您的IDE可能提供类似功能)的最明显方式是查看隐含的内容:
scala> import scala.reflect.runtime.universe.reify
import scala.reflect.runtime.universe.reify
scala> reify { def foo[A:Numeric](d : A) = 2 * d }
res1: reflect.runtime.universe.Expr[Unit] =
Expr[Unit]({
def foo[A](d: A)(implicit evidence$1: Numeric[A]) = implicits.literalIntMultiplicativeSemigroupOps(2).$times(d)(evidence$1);
()
})
查看尖顶来源,我们看到:
final class LiteralIntMultiplicativeSemigroupOps(val lhs: Int) extends AnyVal {
def *[A](rhs:A)(implicit ev: Ring[A]): A = ev.times(ev.fromInt(lhs), rhs)
}
这是一个隐式类,它使*
方法在Int
上可用,前提是右侧的值(代码中为d
)为A
形成Ring
(任何Numeric
A
都会)。所以你的第一个例子有效。但是在第二个例子中没有这样的隐式(没有LiteralDoubleMultiplicativeSemigroupOps
或类似的东西),所以第二个例子没有编译。
答案 1 :(得分:2)
扩展lmm的答案:
将T类型的东西添加或乘以整数,spire只需要spire.algebra.Ring[T]类型类,spire.algebra.Numeric[T]扩展。
中的LiteralIntAdditiveSemigroupOps示例要将T类型的东西添加或乘以double,spire需要spire.algebra.Field[T]类型类的实例,spire.algebra.Numeric[T]执行 不 延伸。
中的LiteralDoubleAdditiveSemigroupOps示例例如将Int添加到T必须是T.所以你需要一种方法将Int转换为T.这适用于spire.algebra.Ring[T](fromInt方法)。要将整数n转换为T,只需使用T的一个元素,并使用T的 + 操作将其求和n次。
例如向T添加Double也必须是T.但是为此您需要一种方法将 Double 转换为T,这更复杂且仅可用在spire.algebra.Field[T]中(fromDouble方法)。看一下Field中的泛型fromDouble方法。这是一些非常复杂的代码,它使用了Field [T]的 div 操作,当然在Ring [T]上不存在。
如果你真的想因为某种原因乘以双倍,你必须修改这样的方法:
def foo[A: Field](d: A) = 2.0 * d