【问题标题】:Scala generic Function vs Generic MethodScala 泛型函数与泛型方法
【发布时间】:2021-02-21 12:51:24
【问题描述】:

到目前为止,我的印象是在 scala 中定义通用函数的唯一方法是使用方法,例如

def myToString[A](value: A) = {println(value)}

但是我想出了以下方法:

val myToStringFun: (T forSome {type T}) => Unit = value => println(value)

有什么我没有看到的,或者是在 Scala 中编写通用函数而不求助于方法的模式?

我以前从未见过这种模式,只是根据我对高等类型和存在主义概念的学习才想出来的......

请分享您对此的想法或智慧......

编辑1:

如果以上是正确的,为什么不使用这种模式,而人们系统地求助于 Method 来实现泛型功能。是否只是为了便于记号

EDIT2:

如果一个函数(T forSome {type T}) => Unit Any => Unit

看来

val mySeqToString: (Seq[T] forSome {type T}) => String = {
    case head +: tail => s"$head +: " + seqToString(tail)
    case Nil => "Nil"
}

等价于

def seqToString[T](seq: Seq[T]): String = seq match {
    case head +: tail => s"$head +: " + seqToString(tail)
    case Nil => "Nil"
}

正确吗?

【问题讨论】:

  • 这不是一个存在的泛型,在这一点上,这只是 Any 的花哨和令人困惑的语法。 T 在任何意义上都不可用,尝试用它编写一个通用标识函数,或者编写一个接受 TTsList 并返回 布尔值的函数 检查列表是否包含该元素。
  • 有趣,所以写def method[F[_]](e: F[T] forSome {type T}): String = ???就像是在说e: F[Any]???
  • Existentials 与 Any 有点不同,特别是因为考虑到对象的变化,它们的行为不同。但是,我个人从来没有发现它们有用(而且,它们总是让我感到惊讶,所以可以说我真的不理解它们)
  • 现有类型也将在 Scala 3 中被删除
  • Scala 3 将拥有正确的polymorphic functions

标签: scala types existential-type


【解决方案1】:

在您的函数中键入A 是标准的泛型类型。你可以用它做很多事情,比如请求一个类型类实例:

import cats.implicits._
def myToString[A: cats.Show](value: A) = { println(value.show) }

另一方面,类型(T forSome {type T})existential type。您可能会通过它更流行的速记符号_(例如List[_])认出它。用那个你无能为力。如果您在

中检查value的类型
val myToStringFun: (T forSome { type T }) => Unit = value => println(value)

您会注意到它是Any。顺便说一句,通过forSome 使用存在类型是being dropped

函数在 Scala 中是单态的,与多态的方法不同。就我个人而言,我认为this 文章对该主题提供了很好的解释。

【讨论】:

    【解决方案2】:

    (T forSome { type T }) 只是Any,所以(T forSome { type T }) => UnitAny => Unit,这是任意A => Unit子类型

    通常F[T] forSome { type T } 不是F[Any](协变FF[+X] 也是如此)。 F[T] forSome {type T} 又名F[_] 是所有类型F[A](包括F[Any])的超类型。实际上,它是最小的超类型,即所有类型F[A] 中的最小上限(对于固定的F 和任意的A)。

    看来

    val mySeqToString: (Seq[T] forSome {type T}) => String = {
      case head +: tail => s"$head +: " + seqToString(tail)
      case Nil => "Nil" 
    }
    

    等价于

    def seqToString[T](seq: Seq[T]): String = seq match {
      case head +: tail => s"$head +: " + seqToString(tail)
      case Nil => "Nil" 
    }
    

    正确吗?

    没有。

    def seqToString[T](seq: Seq[T]): String 是通用的quantification

    seqToString: (∀ T) => (seq: Seq[T]) => String
    

    val mySeqToString: (Seq[T] forSome {type T}) => String 是存在量化

    seqToString: ((∃ T), (seq: Seq[T])) => String
    

    在第一种情况下,您可以指定T,您的代码将适用于这个特定的T,例如seqToString[Int] 将接受 Seq[Int]seqToString[String] 将接受 Seq[String] 等。

    在第二种情况下你不控制T,该方法接受所有Seq[Int]Seq[String]等。

    由于Seq 是协变的,所以Seq[T] forSome { type T } 只是Seq[Any]

    在依赖类型语言中,存在量化 leads 到 Sigma 类型,全称量化导致 Pi 类型。

    【讨论】:

    • 所以这将是一个通用函数但是val mySeqToString: (Seq[T] forSome {type T}) => String = { case head +: tail => s"$head +: " + seqToString(tail) case Nil => "Nil" } ??
    • 编辑了我的问题以添加反映您的答案的第二种情况。
    • 但总的来说,我会坚持使用方法来编写我猜是通用的东西:)
    • 非常感谢您对此进行了扩展。准备好后必须回到这个问题:)
    • @MaatDeamon 是的,我正要评论您的第二个示例与第一个示例并没有太大不同。我可以举一个例子,起初它看起来像一个通用的:val genericFun: ((T, List[T]) forSome {type T}) => Boolean = { case (t, list) => list.contains(t) },快速测试似乎表明它有效:genericFun(3 -> List(1, 3, 5)) 但是,我们可以看到最后它只是 Any 再次使用这个测试:genericFun(3 -> List(1, 0, "")) 同样,主要问题是我们不能在其他参数或返回类型中重用 T
    【解决方案3】:

    Scala 3 (Dotty) 应该提供polymorphic function types,所以类似于多态方法

    scala> def myToString[A](value: A) = println(value)
    def myToString[A](value: A): Unit
    

    我们可以写多态函数

    scala> val myToString: [A] => A => Unit = [A] => (value: A) => println(value)
    val myToString: PolyFunction{apply: [A](x$1: A): Unit} = <function1>
    

    相当于PolyFunction用多态apply方法精化

    scala> val myToString: PolyFunction {def apply[A](value: A): Unit} = new PolyFunction {
         |   def apply[A](value: A): Unit = println(value)
         | }
    val myToString: PolyFunction{apply: [A](value: A): Unit} = <function1>
    

    注意不要混淆多态函数类型

    [A] => B
    

    具有不同“级别”的 lambda 类型

    [A] =>> B
    

    箭头=&gt;&gt; lifts 中的第二个&gt; 到类型级别。

    请注意,此功能仍在根据documentation is missing polymorphic functions #7594 进行开发

    【讨论】:

      猜你喜欢
      • 2017-08-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-12
      • 1970-01-01
      • 2022-01-25
      • 2012-03-05
      • 1970-01-01
      相关资源
      最近更新 更多