Scala 将通用数字函数作为参数传递

Scala pass generic numeric function as parameter

def weirdfunc(message: String, f: (Int, Int) => Int){
            println(message + s" ${f(3,5)}")
          }

我有上面的功能。如何使函数 f 对所有数字类型通用?

抱歉,cktang,您无法对此进行泛化。调用者设置通用参数..而不是被调用函数..就像调用者传递函数参数一样。
但是,您可以使用柯里化,以便传递一次 Int 类型的 'f',然后传递不同的 Int 对。那么你可以传递'f'类型的Double,并传递不同的Double对。

  def weirdfunc[A](message: String, f: (A, A) => A)(x: A, y: A){
    println(message + s" ${f(x, y)}")
  }

  def g(x: Int, y: Int): Int = x * y
  val wierdfuncWithF = weirdfunc("hello", g) _
  wierdfuncWithF(3, 5)
  wierdfuncWithF(2, 3)

特别是你想要的东西不能做,因为它会违反仿制药规则。

你要的是高阶类型(具体来说,2阶)。 Haskell 支持这些类型,Scala 从 Haskell 那里获得了很多类型理论思想,但 Scala 尚未直接支持这一特定功能。

现在,问题是,通过一些黑魔法,我们可以让 Scala 做你想做的事,但语法是……不漂亮。在 Scala 中,函数总是单态的,但你想传递一个多态函数作为参数。我们不能那样做,但是我们可以 传递一个看起来和行为都像函数的类似多态函数的对象。这个对象会是什么样子?

trait NumFunc {
  def apply[A : Numeric](a: A, b: A): A
}

它只是一个定义多态性的特征apply。现在我们可以定义您真正想要的功能了。

def weirdfunc(message: String, f: NumFunc) = ???

正如我提到的,这里的问题是语法真的很糟糕。要调用它,我们不能再只传入一个函数了。我们必须创建一个 NumFunc 并将其传入。本质上,从类型理论的角度来看,我们必须 向编译器证明 我们的函数适用于所有数字 A.例如,调用只取整数并传递加法函数的简单 weirdfunc 非常简单。

weirdfunc("Some message", (_ + _))

但是,要调用适用于所有数字类型的 "special" weirdfunc,我们必须写得这么乱。

weirdfunc("Hi", new NumFunc {
  override def apply[A : Numeric](a: A, b: A): A = {
    import math.Numeric.Implicits._
    a + b
  }
})

而且我们不能通过隐式转换来隐藏它,因为正如我之前提到的,函数是单态的,因此函数类型的任何转换都将是单态的。

底线。可能吗?是的。在可读性和可用性方面值得付出代价吗?可能不是。

Scala 有一个类型类,因此使用上下文绑定和标准库很容易实现。

def weirdfunc[T: Numeric](message: String, x: T, y: T, f: (T, T) => T) {
  println(message + s" ${f(x, y)}")
}

def test[T](a: T, b: T)(implicit ev: Numeric[T]): T = ev.plus(a, b)

weirdFunc[Int]("The sum is ", 3, 5, test)
// The sum is 8