繁体   English   中英

scala 类型不匹配 高级类型

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM