将额外的参数传递给多态函数? [英] Passing an extra argument into a polymorphic function?
问题描述
我有一个多态函数可以把列表变成集合:
import shapeless.PolyDefns.~>进口无形._val 列表 = List(1,2) :: List("A", "B") :: List(1.1, 2.2) :: HNilobject sss extends (List ~> Set) {def apply[T](l:List[T]):Set[T] = {l.toSet}}list.map(sss)//我想要: Set(1,2) :: Set("A", "B") :: Set(1.1, 2.2) :: HNil
但是如果我想改变这个函数的行为怎么办——我现在想添加一个额外的参数来指定应该将输入列表中的哪个项目放入集合中.这是一个不正确的语法 - 你能告诉我正确的方法吗?
object sss extends (List ~> Set) {//编译器说不!def apply[T](i:Int)(l:List[T]):Set[T] = {l.slice(i,i+1).toSet}}
我认为这是失败的,因为额外的参数使它不再适合 List ~> Set 的签名,那么我该如何克服这个问题?
参数化 Poly
有几种解决方法,另一个答案中提到了其中一个,尽管那里的确切实现不会工作.相反,您需要这样做:
import shapeless._, shapeless.poly.~>val 列表 = List(1, 2) :: List("A", "B") :: List(1.1, 2.2) :: HNilclass sss(i: Int) extends (List ~> Set) {def apply[T](l: List[T]): Set[T] = l.slice(i, i+1).toSet}对象 sss1 扩展 sss(1)列表.地图(sss1)
...其中sss1
被定义为对象(不是val
)这一事实对于编译最后一行是必要的.
这种方法可以编译,但不可能在很多上下文中使用它——例如您不能在 hlist 的类型为泛型的方法中定义您的 sss1
(或其他)对象.
这是我以前使用过的一种稍微麻烦但更灵活的解决方法:
import shapeless._val 列表 = List(1, 2) :: List("A", "B") :: List(1.1, 2.2) :: HNil对象 sss 扩展 Poly2 {隐式 def withI[T]: Case.Aux[List[T], Int, Set[T]] =at((l, i) => l.slice(i, i + 1).toSet)}list.zipWith(lists.mapConst(1))(sss)//Set(2) :: Set(B) :: Set(2.2) :: HNil
现在您实际上可以编写一个方法,该方法采用泛型 L <: HList
和切片参数 i
——您只需要几个隐式参数来支持mapConst
和 zipWith
应用程序.
不过,这两种方法都不是很优雅,而且我个人在大多数情况下倾向于避免 Poly
——定义自定义类型类几乎会更简洁,而且在许多情况下是必需的.>
I have a polymorphic function which can turn lists into sets:
import shapeless.PolyDefns.~>
import shapeless._
val lists = List(1,2) :: List("A", "B") :: List(1.1, 2.2) :: HNil
object sss extends (List ~> Set) {
def apply[T](l:List[T]):Set[T] = {
l.toSet
}
}
lists.map(sss) // I want: Set(1,2) :: Set("A", "B") :: Set(1.1, 2.2) :: HNil
But what if I want to change the behavior of this function - I now want to add an extra argument which will specify which item in the input list should be put into the set. Here's an incorrect syntax - can you show me the correct way to do it?
object sss extends (List ~> Set) { // Compiler says no!
def apply[T](i:Int)(l:List[T]):Set[T] = {
l.slice(i,i+1).toSet
}
}
I think this is failing because the additional argument makes it no longer fit the signature of List ~> Set, so how can I overcome this?
There are a couple of workarounds for parametrizing a Poly
, one of which is mentioned in the other answer, although the exact implementation there won't work. Instead you need to do this:
import shapeless._, shapeless.poly.~>
val lists = List(1, 2) :: List("A", "B") :: List(1.1, 2.2) :: HNil
class sss(i: Int) extends (List ~> Set) {
def apply[T](l: List[T]): Set[T] = l.slice(i, i+1).toSet
}
object sss1 extends sss(1)
lists.map(sss1)
…where the fact that sss1
is defined as an object (not a val
) is necessary for the last line to compile.
That approach compiles, but it's not possible to use it in lots of contexts—e.g. you can't define your sss1
(or whatever) object in a method where the type of the hlist is generic.
Here's a slightly messier but more flexible workaround I've used before:
import shapeless._
val lists = List(1, 2) :: List("A", "B") :: List(1.1, 2.2) :: HNil
object sss extends Poly2 {
implicit def withI[T]: Case.Aux[List[T], Int, Set[T]] =
at((l, i) => l.slice(i, i + 1).toSet)
}
lists.zipWith(lists.mapConst(1))(sss)
// Set(2) :: Set(B) :: Set(2.2) :: HNil
Now you could actually write a method that took a generic L <: HList
and the slice parameter i
—you'd just need several implicit arguments to support the mapConst
and zipWith
applications.
Neither approach is very elegant, though, and I personally tend to avoid Poly
most of the time—defining a custom type class is almost going to be cleaner, and in many cases required.
这篇关于将额外的参数传递给多态函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!