Scala没有发现隐式转换

时间:2015-05-13 08:18:28

标签: scala implicit-conversion type-level-computation

我在Map上写了一个包装器:

  • 在类型级别,跟踪地图上存在的键;
  • 强制键和值类型之间的对应关系。

这是代码:

package it.unich.jandom.utils.parametermap

import scala.annotation.implicitNotFound
import scala.language.implicitConversions
import TLists._

object PMaps2 {

  trait Parameter {
    type Value
    def ->(v: Value): (this.type, Value) = (this, v)
  }

  sealed class PMap(val delegate: Map[Parameter, Any]) {
    type PList <: TList

    @implicitNotFound("The parameter map has no element of type ${P}")
    def apply[P <: Parameter](p: P)(implicit ev: Contains[P, PList]) = delegate(p).asInstanceOf[P#Value]
    def get[P <: Parameter](p: P) = delegate.get(p).asInstanceOf[Option[P#Value]]
  }

  object PNil extends PMap(Map.empty[Parameter, Any]) {
    type PList = TNil
    // do not move this in the PMap trait!
    def ::[P <: Parameter](pkey: (P, P#Value)) = new PCons[P, PNil](pkey, this)
  }

  final class PCons[H <: Parameter, T <: PMap](pkey: (H, H#Value), other: T) extends PMap(other.delegate + pkey) {
    type PList = TCons[H,T#PList]
    // do not move this in the PMap trait!
    def ::[P <: Parameter](pkey: (P, P#Value)) = new PCons[P, H :: T](pkey, this)
  }

  type PNil = PNil.type
  type ::[P <: Parameter, T <: PMap] = PCons[P, T]

  implicit def conv[S <: PMap, T <: PMap](m: S)(implicit ev: SubSet[T#PList, S#PList]): T = m.asInstanceOf[T] 
}

TList是类型列表的类型级实现,类似于Metascala中的类型。考虑一下这个使用示例:

import it.unich.jandom.utils.parametermap.PMaps2._
object A extends Parameter { type Value = Int }
object B extends Parameter { type Value = String }
val y = (A -> 3) :: PNil     // has type A.type :: PNil
val x = (B -> "foo") :: y  // has type B.type :: A.type :: PNil
x(B)                         // returns "foo"
// y(B) does not compile
def f(x: A.type :: PNil) = {
  x(A)
}
f(y)   // returns 3
f(conv[B.type :: A.type :: PNil, A.type :: PNil](x))  // returns 3
// f(x) does not compile ------------ WHY?

关键是f(x)不能编译,虽然conv是隐含的,而紧接上面的行是有效的。请注意,如果我从ev: SubSet[T#PList, S#PList]的定义中删除隐式参数conv,则f(x)会进行编译。

我真的不明白为什么会这样。很抱歉这段代码很长,但我无法用一个明显更短的例子来复制这个问题。

0 个答案:

没有答案