Scala相当于Haskel Number

时间:2017-09-29 18:16:59

标签: scala typeclass

以前可能会问过这个问题,我找到了一些旧答案,但我觉得很难接受它们。

我正在尝试编写一个带数字的函数并将它们加在一起:

object Add {
    def[A](a1: A, a2: A) = a1 + a2
}

我收到错误:

[error]  found   : A
[error]  required: String

现在很明显scala没有Hindley-Milner类型推断,但你会期望有一些抽象类,比如说Number,所有的基本操作。如果有我找不到它。 相反,我发现我应该使用类型类:

def add[A](a1: A, a2: A)(implicit n: Numeric[A]) = {
    a1 + a2
}

不起作用......但是:

def add[A](a1: A, a2: A)(implicit n: Numeric[A]) = {
    import n._
    a1 + a2
}

是吗,现在这对我来说似乎并不特别干净。请告诉我有更好的方法!

甚至不使用常规类型类;

def add[A: Numeric](a1: A, a2: A) = {
    a1 + a2
}

有效,我必须添加2行:

def add[A: Numeric](a1: A, a2: A) = {
    val n = implicitly[Numeric[A]]
    import n._
    a1 + a2
}

我觉得我错过了一些基本的东西,因为它不应该这么难添加两个数字

更新

感谢答案,我发现可以做到以下几点:

import scala.math.Numeric._
import scala.math.Numeric.Implicits._

def add[A: Numeric](a1: A, a2: A) = {
    a1 + a2
}

这就是我一直想做的事情。

2 个答案:

答案 0 :(得分:5)

当您需要A为数字的证据时,该证据知道如何对A类型的元素采取行动。

def add[A](a1: A, a2: A)(implicit ev: Numeric[A]) = {
  ev.plus(a1,a2)
}

使用更复杂的中缀符号需要额外的含义。

def add[A](a1: A, a2: A)(implicit ev: Numeric[A]) = {
  import Numeric.Implicits._
  a1 + a2
}
  

甚至不使用普通类型......

应该注意的是你所谓的“常规类型使用”

def add[A: Numeric](a1: A, a2: A) = {...

...实际上是由编译器重写成这样的......

def add[A](a1: A, a2: A)(implicit evidence$1 Numeric[A]) = {...

...除了编译器没有约束到任何特定的名称修改公式,因此您不能依赖具有可预测名称的隐式参数。因此implicitly用于重新实现隐式参数。

答案 1 :(得分:1)

您也可以直接使用Numeric类型方法

def add[A](a1: A, a2: A)(implicit n: Numeric[A]) = {
    n.plus(a1,a2)
}

def add[A: Numeric](a1: A, a2: A) = {
  implicitly[Numeric[A]].plus(a1,a2)
}

为了使用中缀运算符,您需要一个隐式的范围来使用适当的方法将类型A转换为类。这就是我们需要导入类型类提供的隐含的原因。