Scala泛型函数与泛型方法
到目前为止,我的印象是,在scala中定义泛型函数的唯一方法是使用方法,例如Scala泛型函数与泛型方法,scala,types,existential-type,Scala,Types,Existential Type,到目前为止,我的印象是,在scala中定义泛型函数的唯一方法是使用方法,例如 def myToString[A](value: A) = {println(value)} 然而,我的想法如下: val myToStringFun: (T forSome {type T}) => Unit = value => println(value) 是否有我没有看到的东西,或者是在Scala中编写泛型函数而不使用方法的模式 我以前从未见过这种模式,只是根据我对更高级类型的学习和存在主义的概
def myToString[A](value: A) = {println(value)}
然而,我的想法如下:
val myToStringFun: (T forSome {type T}) => Unit = value => println(value)
是否有我没有看到的东西,或者是在Scala中编写泛型函数而不使用方法的模式
我以前从未见过这种模式,只是根据我对更高级类型的学习和存在主义的概念,提出了这种模式
请分享你的想法或智慧
编辑1:
如果上面所说的是正确的,为什么不使用这种模式,人们系统地求助于泛型函数的方法呢。这只是一个简单的符号吗
编辑2:
如果一个函数(T表示某些{type T})=>单元
Any=>单元
然而,似乎
val mySeqToString: (Seq[T] forSome {type T}) => String = {
case head +: tail => s"$head +: " + seqToString(tail)
case Nil => "Nil"
}
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 = seq match {
case head +: tail => s"$head +: " + seqToString(tail)
case Nil => "Nil"
}
正确吗?类型
函数中的A
是标准泛型类型。您可以使用它执行许多操作,例如要求一个typeclass实例:
import cats.implicits._
def myToString[A: cats.Show](value: A) = { println(value.show) }
另一方面,type(T表示某些{type T})
是一种新的类型。您可能会通过它更流行的速记符号来识别它,
(例如列表[\u]
)。你不能用那个。如果在中检查值的类型
val myToStringFun: (T forSome { type T }) => Unit = value => println(value)
您会注意到它是Any
。顺便说一句,对于某些is,通过使用存在类型
函数在Scala中是单态的,不同于多态的方法。就我个人而言,我认为这篇文章对这个主题提供了很好的解释。(T对于某些{type T})
只是Any
,所以(T对于某些{type T})=>Unit
是Any=>Unit
,它是任意a=>Unit
的子类型
通常,一些{type T}
的F[T]不是F[Any]
(协变F
就是这样,即F[+X]
)F[T]对于某些{type T}
akaF[\u]
是所有类型的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"
}
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 = seq match {
case head +: tail => s"$head +: " + seqToString(tail)
case Nil => "Nil"
}
对吗
没有
def seqToString[T](seq:seq[T]):字符串是通用的
而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
是协变的,所以对于某些{type T}
来说,Seq[T]只是Seq[Any]
在依赖类型的语言中,存在量化到Sigma类型,通用量化导致Pi类型。Scala 3(Dotty)应该提供,因此类似于多态方法
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>
注意不要混淆多态函数类型
[A] => B
具有不同“级别”上的lambda类型
其中,箭头=>>
中的第二个
指向类型级别
请注意,此功能仍在按照进行开发,它不是一个存在的泛型,在这一点上,对于任何人来说,它只是一种奇特而混乱的语法。如果T
在任何意义上都不可用,请尝试用它编写一个通用标识函数,或者编写一个函数,该函数接受T
和Ts
列表,并返回一个检查列表是否包含该元素的Boleean。有趣的是,编写def方法[F[\u]](对于某些{type T},e:F[T]):String=??
就像说e:F[Any]
???存在句与任何存在句都有点不同,特别是考虑到对象的变化,它们的行为不同。但是,我个人从未发现它们有用(而且,它们总是让我惊讶,所以公平地说,我真的不理解它们)。存在类型也将在Scala中删除。Scala 3将具有适当的,因此这将是一个通用函数,但是val mySeqToString:(Seq[T]forSome{type T}=>String={case head+:tail=>s“$head+:”+seqToString(tail)case Nil=>“Nil”}
?编辑了我的问题,添加了反映您答案的第二个case。但总的来说,我将坚持使用方法来编写通用的内容,我想:)非常感谢您在这方面的扩展。在做了一些准备之后,我们必须回到这个问题上来:)@MaatDeamon是的,我正要评论你的第二个例子与第一个例子并没有太大的不同。我可以举一个例子,一开始它看起来像一个泛型:val-genericFun:((T,List[T])对于一些{type T}=>Boolean={case(T,List)=>List.contains(T)}
,一个快速测试似乎表明它是有效的:genericFun(3->List(1,3,5))
,我们可以看到,在这个测试的最后,它又一次出现了:genericFun(3->List(1,0,”)
此外,主要的问题是我们不能在其他参数或返回类型中重用T
。