我在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)
会进行编译。
我真的不明白为什么会这样。很抱歉这段代码很长,但我无法用一个明显更短的例子来复制这个问题。