我正在搞乱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)
它似乎工作。但似乎我的第一次尝试应该是等效的,所以我很好奇它失败的原因以及错误信息的含义。
答案 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()方法。