1

我具有以下特征(要获得 2 级多态性click

type Id[A] = A
trait ~>[F[_], G[_]] {
def apply[A](a: F[A]): G[A]
def isDefinedAt[A](a: A): Boolean}

以及将部分函数转换为此特征的函数:

implicit def pft[B: ClassTag](f: PartialFunction[B, B])= new (Id ~> Id) {
def apply[A](a: A): A = f(a.asInstanceOf[B]).asInstanceOf[A]
def isDefinedAt[A: ClassTag](a: A)(implicit ev2: ClassTag[A]) : Boolean = /*type check*/
               f.isDefinedAt(a.asInstanceOf[B]) }

所以我的问题是 isDefinedAt 方法。我必须在运行时检查 A 是否是 B 的实例。a.isInstanceOf[B] 由于类型擦除而不起作用。

我尝试使用 TypeTag/ClassTag 和 B 效果很好,但 A 的类型总是 Any。

那么,如何检查 A 是否是 B 的实例?

更新:我在这段代码中使用它:

  def map[A](f: Id ~> Id, x: A): A =
    {
      val y = x match {
        //many matches more on my own data structures
        case l : List[_] => l.map(map(f,_))
        case m : Map[_,_] => m.map(map(f,_))
        case (a,b) => (map(f,a),map(f,b))
        case a => a
      }
      if (f.isDefinedAt(y))
        f(y).asInstanceOf[A]
      else
        y.asInstanceOf[A]
    }

如果我直接使用 ~>,那么 typeTag[A].tpe <:< typeTag[B].tpe 一切正常。

但是如果我将它与这个映射函数一起使用,typeTag[A].tpe 总是 Any。

4

1 回答 1

1

如果您可以修改 isDefinedAt 的签名以采用 TypeTag,则可以通过以下方式实现 pft:

  type Id[A] = A
  trait ~>[F[_], G[_]] {
    def apply[A](a: F[A]): G[A]
    def isDefinedAt[A: TypeTag](a: A): Boolean
  }

  implicit def pft[B: TypeTag](f: PartialFunction[B, B]) = new (Id ~> Id) {
    def apply[A](a: A): A = f(a.asInstanceOf[B]).asInstanceOf[A]
    def isDefinedAt[A: TypeTag](a: A): Boolean =
      typeTag[A].tpe =:= typeTag[B].tpe && f.isDefinedAt(a.asInstanceOf[B])
  }

此解决方案为两者获取一个TypeTagB ,并在委托给部分函数的方法A之前验证它们是否为同一类型。isDefinedAt有关类型标签的更多信息,请参阅此答案

例如:

val halfEven: PartialFunction[Int, Int] = {
  case n if n % 2 == 0 => n / 2
}

val halfEvenT: Id ~> Id = halfEven

halfEvenT.isDefinedAt(1) // false
halfEvenT.isDefinedAt(2) // true
halfEvenT.isDefinedAt("test") // false

更一般地说,您可以将受约束的部分转换定义为采用额外的更高种类的约束A

  trait ConstrainedPartialTransformation[F[_], G[_], C[_]] {
    def apply[A: C](a: F[A]): G[A]
    def isDefinedAt[A: C](a: A): Boolean
  }

  implicit def cpft[B: TypeTag](f: PartialFunction[B, B]) = new ConstrainedPartialTransformation[Id, Id, TypeTag] {
    def apply[A: TypeTag](a: A) = f(a.asInstanceOf[B]).asInstanceOf[A]
    def isDefinedAt[A: TypeTag](a: A) =
      typeTag[A].tpe =:= typeTag[B].tpe && f.isDefinedAt(a.asInstanceOf[B])
  }

这类似于 Scalaz 7 如何支持 A 上的上下文绑定的自然转换。请参阅Scalaz 7 中的ConstrainedNaturalTransformation

于 2013-03-16T18:18:12.703 回答