2013-03-16 45 views
1

值我有以下特點(以獲得各種級別2多態性click)的檢查是否在Scala中的部分功能definied與不明類型

type Id[A] = A 
trait ~>[F[_], G[_]] { 
def apply[A](a: F[A]): G[A] 
def isDefinedAt[A](a: A): Boolean} 

和一個功能轉換的部分功能,這特徵:

implicit def pft[B: ClassTag](f: PartialFunction[B, B])= new (Id ~> Id) { 
def apply[A](a: A): A = f(a.asInstanceOf[B]).asInstanceOf[A] 
def isDefinedAt[A: ClassTag](a: A)(implicit ev2: ClassTag[A]) : Boolean = /*type check*/ 
       f.isDefinedAt(a.asInstanceOf[B]) } 

所以我的問題是isDefinedAt方法。我必須在運行時檢查A是否是B的一個實例。 a.isInstanceOf [B]由於類型擦除而不起作用。

我試着使用TypeTag/ClassTag和B工作得很好,但類型爲A ist永遠任何。

那麼,如何檢查A是B的一個實例呢?

更新:我用它在此代碼:

def map[A](f: Id ~> Id, x: A): A = 
    { 
     val y = x match { 
     //many matches more on my own data structures 
     case l : List[_] => l.map(map(f,_)) 
     case m : Map[_,_] => m.map(map(f,_)) 
     case (a,b) => (map(f,a),map(f,b)) 
     case a => a 
     } 
     if (f.isDefinedAt(y)) 
     f(y).asInstanceOf[A] 
     else 
     y.asInstanceOf[A] 
    } 

如果我使用了〜>​​直接的一切工作正常與typeTag [A] .tpe <:< typeTag [B] .tpe。

但是,如果我使用它與這個映射函數,typeTag [A] .tpe總是任何。

回答

1

如果你是好與修改isDefinedAt的簽名採取TypeTag,可以實現PFT這樣:

type Id[A] = A 
    trait ~>[F[_], G[_]] { 
    def apply[A](a: F[A]): G[A] 
    def isDefinedAt[A: TypeTag](a: A): Boolean 
    } 

    implicit def pft[B: TypeTag](f: PartialFunction[B, B]) = new (Id ~> Id) { 
    def apply[A](a: A): A = f(a.asInstanceOf[B]).asInstanceOf[A] 
    def isDefinedAt[A: TypeTag](a: A): Boolean = 
     typeTag[A].tpe =:= typeTag[B].tpe && f.isDefinedAt(a.asInstanceOf[B]) 
    } 

該解決方案得到了雙方BA一個TypeTag並驗證它們是相同的在委託給部分函數的isDefinedAt方法之前鍵入。有關類型標籤的更多信息,請參閱this answer

例如:

val halfEven: PartialFunction[Int, Int] = { 
    case n if n % 2 == 0 => n/2 
} 

val halfEvenT: Id ~> Id = halfEven 

halfEvenT.isDefinedAt(1) // false 
halfEvenT.isDefinedAt(2) // true 
halfEvenT.isDefinedAt("test") // false 

更一般地,可以定義一個約束部分轉變爲採取該約束A額外更高kinded類型:

trait ConstrainedPartialTransformation[F[_], G[_], C[_]] { 
    def apply[A: C](a: F[A]): G[A] 
    def isDefinedAt[A: C](a: A): Boolean 
    } 

    implicit def cpft[B: TypeTag](f: PartialFunction[B, B]) = new ConstrainedPartialTransformation[Id, Id, TypeTag] { 
    def apply[A: TypeTag](a: A) = f(a.asInstanceOf[B]).asInstanceOf[A] 
    def isDefinedAt[A: TypeTag](a: A) = 
     typeTag[A].tpe =:= typeTag[B].tpe && f.isDefinedAt(a.asInstanceOf[B]) 
    } 

這類似於如何Scalaz 7個支持自然轉換,其中上下文綁定在A上。請參閱Scalaz 7的ConstrainedNaturalTransformation

+0

感謝您的回答!我現在看到,我說這個問題很簡單。我的問題還在於我如何使用這種轉換。 我嘗試了基本相同的第一個解決方案,並獲得typeTag [A] .tpe =任何與我的代碼。我會盡快更新我的問題。 我現在沒有如何使用你的第二個解決方案(沒有TypeTag可用於Int) – schlicht 2013-03-17 08:48:48

+0

啊,我明白了。 Any被推斷的原因是編譯器沒有關於映射函數體內的List或Map類型參數的任何信息。 – mpilquist 2013-03-17 13:23:28

+0

考慮部分函數:'val pf:PartialFunction [List [Int],List [Int]] = {case l => l.reverse}'。這個例子應該用'map'做什麼?它看起來像map函數假定傳遞給它的'〜>是爲不帶參數的類型定義的。我可以讓'map'在這個假設下工作,但我想知道應該以不同的方式解決問題嗎?也許重申你正在嘗試做什麼? – mpilquist 2013-03-17 14:48:55

相關問題