4

I've been experimenting with MacroParadise (here and here), as well a few other newer features. Today while using TypeTags, I came to the realization that I can now do something like this to enforce type equality.

def typeEq[A: TypeTag, B: TypeTag]: Boolean = {
    implicitly[TypeTag[A]].tpe =:= implicitly[TypeTag[B]].tpe
}

I then remembered that TypeTag implicits are compiler generated, and I had the idea that I may be able write a macro enabling more concise TypeTag usage like this:

def foo[A](xs: List[A]): String = xs match {
  case y :: ys if typeEq[A, String] => y
  case y :: ys if typeEq[A, Int]    => y.toString 
} 

I've only written a handful of macros in Lisp, and am stumbling around attempting to use the macro library. This lead me to several attempts, but they all end up expanding to something like Int =:= Int which doesn't work, or something like typeA =:= typeB where both are free(which also doesn't work).

This lead me to two questions: 1) Is this possible to do without the Context Bounds on foo(like written above)? 2) How do I correctly splice the Types obtained by the implicits into the result expression?

It seems to me that macros and implicits should allow me to fetch the WeakTypeTag implicit and use its tpe member for splicing, since they both occur at compile time.

4

1 に答える 1

3

type を使用して、すでに型の等価性を強制できます=:=[From,To]

def bar[A,B](a:A,b:B)(implicit ev: A =:= B)= (a,b)

bar(1,1)
res0: (Int, Int) = (1,2)

bar(1,"3")

error: could not find implicit value for parameter ev: =:=[Int,java.lang.String]
       bar(1,"3")
          ^

編集

申し訳ありませんが、あなたの質問は少し間違っていたと思います。あなたの例はほとんど機能しますが、コンパイラは何が何でAあるかを知ることができないため、の証拠を見つけることができませんTypeTag[A]。メソッド定義にバインドされたコンテキストを追加すると、機能します。

def foo[A : TypeTag](xs: List[A]) = xs match {
  case _ if typeEq[A, String] => "yay"
  case _ => "noes"
}

scala> foo(List(2))
res0: String = noes

scala> foo(List(""))
res1: String = yay

edit2 :

あなたの例では、実際にはTypeTags はまったく必要ありません。最初の要素のみを使用するため、パターン マッチングを使用できます。

def foo[A](xs: List[A]): String = xs match {
  case (y: String) :: _ => y
  case y :: _ => y.toString
}

scala> foo(List(1,2,3))
res6: String = 1

scala> foo(List("foo"))
res7: String = foo

ただし、パターン マッチングは を処理しないため、網羅的ではないことに注意してくださいNil

于 2013-02-21T07:31:19.823 に答える