我正在和Scala 2.8乱七八糟,并试图定义一个 拉皮条 它添加了一种键入构造函数的“ 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)

而且它似乎有效。但是看来我的第一次尝试应该是等效的,所以我很好奇它为什么失败以及错误消息的含义。

有帮助吗?

解决方案

我的直觉是,这是因为由于规格中的以下陈述,第6.11节,块:

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

并将结构实例的创建表达式评估为一个块,因此


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

是一个速记


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

因此,它对块表达式(根据规格的第6.10节)进行评估,并具有上述限制。但是,为什么我不知道这种限制。在打字机类中可以找到错误的错误 这个位置, ,这似乎证实了这一限制是您看到的错误的原因。如您提到的,在类中编码该函数可删除块表达式限制:


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}

其他提示

对我来说,这听起来像是对普遍案例的简单性:每次创建一个块时,可能会生成一个新的类型变量,以捕获与存在类型实例化的某种类型的构造函数,但这会使错误诊断更难理解。

另请注意,让班级将呼叫变成快速的调用,而不是调用 作为() 方法反射。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top