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
但未应用。