2010-06-26 63 views
11

我正在搞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) 

,它似乎工作。但似乎我的第一次尝试应该是相同的,所以我很好奇它为什么失败以及错误消息的含义。

+1

我已经习惯了在类似情况下看到错误“结构细化中的参数类型可能不涉及在该细化之外定义的抽象类型”。这种限制与结构类型在JVM上用反射IIRC实现的方式有关。 http://stackoverflow.com/questions/2685804/scala-parameter-type-in​​-structural-refinement-may-not-refer-to-an-abstract-type – retronym 2010-06-26 06:30:23

回答

10

我的预感会,这是因为由于在spec下面的语句,§ 6.11,块:

本地定义类型定义类型T = T由存在子句 类型吨结合>:T <:T。如果t携带类型参数,那是错误的。

和结构实例创建表达进行评估,以一个块,所以


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

是(根据§ 6.10的为


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

所以一个速记它的计算结果为一个块表达式规范),与上述限制。但是,为什么这个限制是我不知道的。抛出的错误可以在Typers类的this location处找到,这似乎证实了这个限制是你看到的错误的原因。 如你所提到的,在一个类的编码函数删除块表达限制:


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} 

0

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

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

相关问题