2013-07-20 11 views
9

2つの "コンテナ"が同じ高級型を使用しているかどうかをテストしようとしています。次のコードを見て:しかし、私はコンフォーマンステストが成功することを期待Scalaで高級型の型適合性をテストする方法

false 
Test.Funct[Option,Int] 
scala.Option[_] 

import scala.reflect.runtime.universe._ 

class Funct[A[_],B] 

class Foo[A : TypeTag](x: A) { 
    def test[B[_]](implicit wt: WeakTypeTag[B[_]]) = 
    println(typeOf[A] <:< weakTypeOf[Funct[B,_]]) 

    def print[B[_]](implicit wt: WeakTypeTag[B[_]]) = { 
    println(typeOf[A]) 
    println(weakTypeOf[B[_]]) 
    } 
} 

val x = new Foo(new Funct[Option,Int]) 

x.test[Option] 
x.print[Option] 

出力されます。私は間違って何をしていますか?より親切なタイプのテストはどのようにすればいいですか?私の場合は

明確化

、私は(この例でx: A)をテストしていた値は、マクロでList[c.Expr[Any]]に来ます。静的な解像度(私が与えたもの)に頼っている解決策は、私の問題を解決しません。

+1

暗黙のうちに[Funct [Option、Int] <: pedrofurla

+0

https://gist.github。com/xeno-by/6054650型参照元がB型の型タグを認識しないので、weakTypeOf [Funct [B、_]]から正しい型を取得できないことがわかります。 –

+0

さて、問題は何か分かりました。これは、型パラメータ定義で使用されたアンダースコアと他の場所とのミックスアップです。 'TypeTag [B [_]]のアンダースコアは実在する型を意味するので、' B'ではなく、実在するラッパーの型タグを取得します。その結果、 'typeOf [Funct [B、_]]'はこのタイプタグを使うことができず、動揺します。 –

答えて

8

それは、アンダースコア間の重複が整理だpedrofurlaのヒント@から窃盗、およびタイプ・クラスを使用して

型パラメータ定義などで使用されます。 TypeTag[B[_]]のアンダースコアは存在タイプを意味するので、Bのタグではなく、その上に存在するラッパーのために、手動の後処理なしではほとんど役に立たないタグを取得します。

したがって、生のタグBを必要とするtypeOf[Funct[B, _]]は、ラッパーのタグを使用できず、不調になります。私はそれが範囲内のタグをスプライスすることを拒否し、コンパイルエラーで失敗することを意味して怒っていることによって。 weakTypeOfを代わりに使用すると、それは成功しますが、スプライスできなかったものすべてに対してスタブが生成され、結果をサブタイプチェックに使用できなくなります。

Scalaの多様性がないのでBWeakTypeTag[B]で参照する方法がないという意味で、この場合のように見えます。うまくいけば、DOTのようなものがこの不便さから​​私たちを救うでしょうが、その間にこの回避策を使用することができます(それはかなりではありませんが、もっと簡単なアプローチを考え出すことができませんでした)。

import scala.reflect.runtime.universe._ 

object Test extends App { 
    class Foo[B[_], T] 
    // NOTE: ideally we'd be able to write this, but since it's not valid Scala 
    // we have to work around by using an existential type 
    // def test[B[_]](implicit tt: WeakTypeTag[B]) = weakTypeOf[Foo[B, _]] 
    def test[B[_]](implicit tt: WeakTypeTag[B[_]]) = { 
    val ExistentialType(_, TypeRef(pre, sym, _)) = tt.tpe 

    // attempt #1: just compose the type manually 
    // but what do we put there instead of question marks?! 
    // appliedType(typeOf[Foo], List(TypeRef(pre, sym, Nil), ???)) 

    // attempt #2: reify a template and then manually replace the stubs 
    val template = typeOf[Foo[Hack, _]] 
    val result = template.substituteSymbols(List(typeOf[Hack[_]].typeSymbol), List(sym)) 
    println(result) 
    } 
    test[Option] 
} 

// has to be top-level, otherwise the substituion magic won't work 
class Hack[T] 

鋭い読者は、私がTypeTagを使用することができなければならないにもかかわらず、私はfooの署名でWeakTypeTagを使用したことに気づくであろう。結局のところ、fooはOptionというふうに動作する型です。つまり、解決されない型のパラメータや、TypeTagで問題となるローカルクラスは含まれていません。残念ながら、https://issues.scala-lang.org/browse/SI-7686のため単純ではありません。したがって、必要がないにもかかわらず弱いタグを使用する必要があります。

+0

Fooを介して抽象化することはできますか? – Edmondo1984

5

以下は、私が与えた(そして他人を助けるかもしれない)例では機能しますが、私の(単純化されていない)ケースには該当しません。

trait ConfTest[A,B] { 
    def conform: Boolean 
} 

trait LowPrioConfTest { 
    implicit def ctF[A,B] = new ConfTest[A,B] { val conform = false } 
} 

object ConfTest extends LowPrioConfTest { 
    implicit def ctT[A,B](implicit ev: A <:< B) = 
    new ConfTest[A,B] { val conform = true } 
} 

そしてFooにこれを追加します:

def imp[B[_]](implicit ct: ConfTest[A,Funct[B,_]]) = 
    println(ct.conform) 

を:

x.imp[Option] // --> true 
x.imp[List] // --> false