Scala 它的混乱
编译以下多态方法:Scala 它的混乱,scala,spire,Scala,Spire,编译以下多态方法: 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.mat
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
更改为双精度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
^
scala>def foo[A:Numeric](d:A)=2.0+d
:19:错误:找不到参数ev:spire.algebra.Field[A]的隐式值
def foo[A:数字](d:A)=2.0+d
^
scala>def foo[A:Numeric](d:A)=2.0*d
:19:错误:找不到参数ev:spire.algebra.Field[A]的隐式值
def foo[A:数字](d:A)=2.0*d
^
我试图理解其他一些问题和答案,但我并不知道如何解决这个问题。我发现最清晰的方法是使用
具体化(您的IDE可能提供类似的功能):
从塔尖上看,我们看到:
final class LiteralIntMultiplicativeSemigroupOps(val lhs: Int) extends AnyVal {
def *[A](rhs:A)(implicit ev: Ring[A]): A = ev.times(ev.fromInt(lhs), rhs)
}
这是一个隐式类,它使*
方法在Int
s上可用,前提是右边的值(d
在代码中)是一些a
,它形成了一个环(任何数值a
都会)。所以你的第一个例子是有效的。但是在第二个示例中没有这样的隐式(没有LiteralDoubleMultiplicativeSemigroupOps
或类似内容),因此第二个示例没有编译。我发现最清晰的方法是使用具体化
(您的IDE可能提供类似的功能):
从塔尖上看,我们看到:
final class LiteralIntMultiplicativeSemigroupOps(val lhs: Int) extends AnyVal {
def *[A](rhs:A)(implicit ev: Ring[A]): A = ev.times(ev.fromInt(lhs), rhs)
}
这是一个隐式类,它使*
方法在Int
s上可用,前提是右边的值(d
在代码中)是一些a
,它形成了一个环(任何数值a
都会)。所以你的第一个例子是有效的。但是在第二个示例中没有这样的隐式(没有LiteralDoubleMultiplicativeSemigroupOps
等),因此第二个示例没有编译。要扩展lmm的答案:
要将T类型的某个值与整数相加或相乘,spire只需要扩展的typeclass
请参见中的文字累加性半组操作示例
要将T类型的内容添加或相乘到double,spire需要typeclass的一个实例,该实例不扩展
请参见中的LiteralDoubleAdditiveSemigroupOps示例
做出此设计决策的原因:
例如,将Int添加到T的结果必须是T。因此您需要一种将Int转换为T的方法。这适用于(fromInt方法)。要将整数n转换为T,只需使用T的一个元素,并使用T的+运算将其求和n次
例如,向T添加一个Double的结果也必须是T。但为此,您需要一种将Double转换为T的方法,这种方法要复杂得多,并且仅在(fromDouble方法)中可用。查看字段中的泛型fromDouble方法。这是一个相当复杂的代码,它使用了字段[T]的div操作,当然环[T]上不存在该操作
如何修改代码
如果出于任何原因,您真的想与double相乘,则必须修改如下方法:
def foo[A: Field](d: A) = 2.0 * d
要扩展lmm的答案,请执行以下操作:
要将T类型的某个值与整数相加或相乘,spire只需要扩展的typeclass
请参见中的文字累加性半组操作示例
要将T类型的内容添加或相乘到double,spire需要typeclass的一个实例,该实例不扩展
请参见中的LiteralDoubleAdditiveSemigroupOps示例
做出此设计决策的原因:
例如,将Int添加到T的结果必须是T。因此您需要一种将Int转换为T的方法。这适用于(fromInt方法)。要将整数n转换为T,只需使用T的一个元素,并使用T的+运算将其求和n次
例如,向T添加一个Double的结果也必须是T。但为此,您需要一种将Double转换为T的方法,这种方法要复杂得多,并且仅在(fromDouble方法)中可用。查看字段中的泛型fromDouble方法。这是一个相当复杂的代码,它使用了字段[T]的div操作,当然环[T]上不存在该操作
如何修改代码
如果出于任何原因,您真的想与double相乘,则必须修改如下方法:
def foo[A: Field](d: A) = 2.0 * d
存在此隐式:LiteralDoubleMultiplicativeSemigroupOps
但未应用。存在此隐式:LiteralDoubleMultiplicativeSemigroupOps
但未应用。