[英]scala type mismatch Higher kinded type
我想对一个Mapper
进行建模,该Mapper
接收A
s ( T[A]
) 的容器,以便使用f: A => B
的函数我们得到另一个容器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)
}
我现在可以按如下方式使用它:
import Mappers.IntMapper
val l9 = testMapper( List( 1, 2, 3 ), { x: Int => x + 1 } )
println(l9)
尽管它有效,但我仍然不知道如何将 Out 直接限制为T[B]
。 如果我这样做,我似乎总是会遇到类型不匹配的情况。 任何人都可以指出一种更清晰/更简单的方法来做到这一点,而无需类型别名或直接使用T[B]
吗?
TIA
这是您想要的第一个近似值的评论。 类型成员被淘汰了,揭示了你想要做什么的一个更深层次的问题。
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.
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.