使用多态函数作为参数

问题描述 投票:2回答:2

我有一个函数exec,它接受3个参数,并将作为第一个参数传递的函数f应用于其他两个参数p1p2

  def exec[T](f: (T, T) => Boolean, p1: T, p2: T) = f(p1, p2)

如果我事先声明一个将作为参数传递的函数,那么一切都很好。

以某种方式,编译器可以推断eq的参数类型,换句话说,它可以确定whatever在这种情况下为Int

  // declaring a function with type parameter (polymorphic method)
  def eq[whatever](p1: whatever, p2: whatever) = p1 == p2
  // using a declared function
  println(exec(eq, 10, 10))

如果我明确指定Int,如下所示,它也可以正常工作

  // specifying type explicitly in function literal
  println(exec((p1: Int, p2: Int) => p1 == p2, 10, 10))
  // specifying type parameter
  println(exec[Int]((p1, p2) => p1 == p2, 10, 10))

问题1

是否有可能低于正常工作?

println(exec((p1, p2) => p1 == p2, 10, 10))

例如,通过使用隐式,不同地定义exec或使用其他某种方式,使编译器可以推断p1和p2的类型,以便它不会因missing parameter type而失败。

因此,不使用显式类型提示或声明的方法。

问题2

编译器如何推断eq的类型,以及为什么它适用于p1 == p2p1 != p2之类的表达式,但对于p1 >= p2却失败(错误为value >= is not a member of type parameter whatever)?

scala generics type-inference
2个回答
1
投票

问题1是否可以使工作低于正常水平?

如果您可以这样重写exec

def exec[T](p1: T, p2: T)(f: (T, T) => Boolean) = f(p1, p2)

然后,编译器将已经知道函数的输入类型。因此,您可以这样称呼它:

println(exec(10, 10) { case (p1, p2) => p1 == p2 })

这是一个常见的习惯用法,首先将普通参数放在一个参数组上,然后再将函数放在单个参数组上。

编译器如何推断eq的类型以及为什么它适用于p1 == p2或p1!= p2之类的表达式,但对于p1> = p2则失败

因为,Scala具有普遍平等(这是人们最批评该语言的东西之一,但对于Java互操作来说是必需的。)]

因此,您始终可以比较任何类的两个对象以确保相等。这是因为在Any

超类中定义了相等性,如下所示。
class Any {
  def equals(other: Any): Boolean
}

但是,订购不是普遍的。如果需要,您可能想编写一个适用于任何类型的泛型函数,只要有这种类型的顺序即可,您可能会对Ordering-Ordering感兴趣。但这是另一个问题的话题。


1
投票

Scala 3(点状)将能够推断typeclass中的类型,而不必依赖多个参数列表来进行推断

© www.soinside.com 2019 - 2024. All rights reserved.