我想建模Mapper
,其中包含A
s(T[A]
)的容器,以便使用f: A => B
函数获取另一个容器{{ 1}}。经过几个小时的实验(参见注释代码),我得出了以下解决方案:
T[B]
我现在可以按如下方式使用它:
sealed trait Mapper[ A, T[ A ], B ] {
//type Out <: T[B]
type Out[X] //= T[X]
def map( l: T[ A ], f: A => B ): Out[B]
}
object Mappers {
implicit def typedMapper[ A, T[ A ] <: Iterable[ A ], B ]: Mapper[ A, T, B ] =
new Mapper[ A, T, B ] {
override type Out[X] = Iterable[X]
//override type Out <: Iterable[ B ]
//def map( l: T[ A ], f: A => B ) : this.Out = {
def map( l: T[ A ], f: A => B ) : Out[B] = {
println( "map" )
l.map( f )
}
}
implicit def IntMapper = typedMapper[Int, List, Int]
}
//def testMapper[ A, T[ A ], B ]( l: T[ A ], f: A => B )( implicit mapper: Mapper[ A, T, B ] ): T[B] = {
def testMapper[ A, T[ A ], B ]( l: T[ A ], f: A => B )( implicit mapper: Mapper[ A, T, B ] ) : Mapper[A, T, B]#Out[B]= {
println( mapper )
mapper.map(l, f)
}
虽然它有效但我仍然不知道如何直接将Out限制为import Mappers.IntMapper
val l9 = testMapper( List( 1, 2, 3 ), { x: Int => x + 1 } )
println(l9)
。如果我这样做,我似乎总是得到类型不匹配。任何人都可以在没有类型别名或直接使用T[B]
的情况下指出更清晰/更简单的方法吗?
TIA
答案 0 :(得分:1)
这是对你想要的评论的第一个近似值。类型成员已被淘汰,在您想要做的事情中显示出稍微深一些的问题。
trait Mapper[A, T[_], B] {
def map(ta: T[A])(f: A => B): T[B]
}
// Note that Iterable[A]#map has type [B](A => B)Iterable[B]. You can't have typedMapper
// like yours from above just yet, because T#map is not certain to return another T;
// it only promises an Iterable.
implicit def iterableMapper[A, B]: Mapper[A, Iterable, B] = new Mapper[A, Iterable, B] {
// Multiple param lists support the type inferencer
override def map(i: Iterable[A])(f: A => B) = i.map(f)
}
// Curried and arg-swapped version of Mapper
type MapperOf[A, B] = { type l[T[_]] = Mapper[A, T, B] }
def map[A, B, T[_]: MapperOf[A, B]#l](ta: T[A])(f: A => B): T[B] = implicitly[Mapper[A, T, B]].map(ta)(f)
map(??? : Iterable[Any])(_.toString) // OK (at compile time, at least :P)
map(List(1,2,3))(_*2) // NOPE! The inferencer has already decided T = List, before
// looking for implicits, so the resolution fails to notice that
// iterableMapper would work.
map[Int, Int, Iterable](List(1,2,3))(_*2) // Works
这推动了类型推理器的限制,这就是你需要手动指定类型参数的原因。
请注意,Iterable
对集合层次结构并不重要。它主要是因为Java拥有它。为了使它对于集合来说是通用的,你需要一些美味的CanBuildFrom
黑暗魔法。
import collection._, generic._ // Open the gates of hell
implicit def collectionMapper[A, Coll[A] <: GenTraversableLike[A, Coll[A]], B]
(implicit builderFactory: CanBuildFrom[Coll[A], B, Coll[B]]):
Mapper[A, Coll, B] =
new Mapper[A, Coll, B] {
override def map(coll: Coll[A])(f: A => B): Coll[B] = coll.map(f)
}
map(List(1))(_*2): List[Int] // Works
map(Seq(1).view)(_*2): Seq[Int] // Works, but note how we lose the knowledge of the view
// Exercise for the reader: fix that.
map(BitSet(1))(_*2): SortedSet[Int] // Works, but we lose the BitSet-ness
// Another exercise: fix it.