“不能存在抽象的参数化类型...”

时间:2010-06-26 01:55:50

标签: scala typeclass functor implicits

我正在搞乱Scala 2.8以获得乐趣,并尝试定义一个pimp,它为类型构造函数添加了一个“as”方法,允许从一个仿函数转换为另一个仿函数(请忽略我是这样的事实不一定在这里处理仿函数)。例如,您可以像这样使用它:

val array:Array[T]
val list:List[T] = array.as[List]

所以这就是我试图做的事情:

object Test {
    abstract class NatTrans[F[_], G[_]] {
        def convert[T](f:F[T]):G[T]
    }

    implicit def array2List:NatTrans[Array, List] = new NatTrans[Array, List] { 
        def convert[T](a:Array[T]) = a.toList
    }

    // this next part gets flagged with an error
    implicit def naturalTransformations[T, F[_]](f:F[T]) = new {
        def as[G[_]](implicit n:NatTrans[F, G]) = n convert f
    }
}

然而naturalTransformations的定义被标记为错误“不能存在抽象的参数化类型G [T]”。要解决此问题,我可以重写naturalTransformations以及其他类Transformable,如下所示:

class Transformable[T, F[_]](f:F[T]) {
    def as[G[_]](implicit n:NatTrans[F, G]) = n convert f
}

implicit def naturalTransformations[T, F[_]](f:F[T]) = new Transformable[T, F](f)

它似乎工作。但似乎我的第一次尝试应该是等效的,所以我很好奇它失败的原因以及错误信息的含义。

2 个答案:

答案 0 :(得分:11)

我的预感是,这是因为由于规范中的以下陈述,§6.11,块:

  

本地定义的类型定义类型t = T由existential子句绑定   类型t>:T<:T。如果t携带类型参数,则会出错。

结构实例创建表达式被计算到块,所以


new {def greet{println("hello")}}

的简写

{ class anon$X extends AnyRef{ def greet = println("hello") }; new anon$X }

因此它评估为块表达式(根据规范的第6.10节),具有上述限制。然而,为什么这个限制是我不知道的。抛出的错误可以在this location的Typers类中找到,这似乎可以确认此限制是您看到的错误的原因。 如前所述,在类中编码函数会删除块表达式限制:


scala> class N[M[_]]
defined class N

scala> class Q { def as[M[_]](n:N[M]) = null}
defined class Q

scala> new { def as[M[_]](n:N[M]) = null}       
:7: error: can't existentially abstract over parameterized type M
       new { def as[M[_]](n:N[M]) = null}

答案 1 :(得分:0)

对我来说,这听起来像是一般性情况下的简单:每次创建一个块时都会生成一个新的类型变量,捕获一些用存在类型实例化的类型构造函数,但这会使错误诊断更难以理解。

另请注意,拥有一个类会将调用转换为快速INVOKEVIRTUAL,而不是通过反射调用 as()方法。