2010-06-26 61 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,而不是通過反射調用方法()

相關問題