9

2 つの「コンテナー」が同じ高次型を使用しているかどうかをテストしようとしています。次のコードを見てください。

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]

出力は次のとおりです。

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

ただし、コンフォーマンス テストは成功すると思います。私は何を間違っていますか?より高次の型をテストするにはどうすればよいですか?

明確化

私の場合、テストしている値 (x: A例では)List[c.Expr[Any]]はマクロに含まれています。そのため、静的解像度 (私が与えたもの) に依存するソリューションは、私の問題を解決しません。

4

2 に答える 2

8

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

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

この場合、Scala には種類のポリモーフィズムがないため、 でrawBを参照する方法がないという意味で、本当に Scala の限界に達しているように見えます。DOTWeakTypeTag[B]のようなものがこの不都合から私たちを救ってくれることを願っていますが、それまでの間、この回避策を使用できます (きれいではありませんが、私はより簡単なアプローチを思い付くことができませんでした)。

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]

賢明な読者は、私が を使用できるはずなのに、WeakTypeTagの署名にを使用していることに気付くでしょう。結局のところ、未解決の型パラメーターや s に問題を引き起こすローカル クラスを含まないという意味で、行儀の良い型であるan に対して foo を呼び出します。残念ながら、 https://issues.scala-lang.org/browse/SI-7686のせいでそれほど単純ではありません。そのため、必要のないはずの弱いタグを使用せざるを得ません。fooTypeTagOptionTypeTag

于 2013-07-22T15:50:30.633 に答える
5

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

@pedrofurla のヒントを盗み、型クラスを使用する:

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
于 2013-07-21T18:46:57.420 に答える