【问题标题】:Using polymorphic function as a parameter使用多态函数作为参数
【发布时间】:2020-09-19 06:24:25
【问题描述】:

我有一个函数 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


    【解决方案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 - typeclass 感兴趣。
    但这是另一个问题的主题。

    【讨论】:

    • 谢谢!一个小的补充 - 不需要匿名部分函数。它也像这样工作println(exec(10, 10)((p1, p2) => p1 == p2))
    • 快速描述为什么在 Scala 2 中需要currying 在这种情况下进行类型派生 - docs.scala-lang.org/tour/multiple-parameter-lists.html
    【解决方案2】:

    Scala 3 (dotty) 将能够推断exec 中的类型,而无需依赖多个参数列表来帮助推断

    scala> def exec[T](f: (T, T) => Boolean, p1: T, p2: T) = f(p1, p2)
         | exec((p1, p2) => p1 == p2, 10, 10)
    def exec[T](f: (T, T) => Boolean, p1: T, p2: T): Boolean
    val res0: Boolean = true
    

    【讨论】:

    • 记得我前几天的评论说“总体改进”,你有一个:p
    • @LuisMiguelMejíaSuárez 考虑将其添加为那里的答案。这将是一个很好的例子。
    • 我相信最好的答案是让它成为社区答案,您可以在找到示例时继续添加示例。
    • @LuisMiguelMejíaSuárez stackoverflow.com/a/62184556/5205022
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-08
    • 1970-01-01
    • 1970-01-01
    • 2018-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多