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

编辑2

对于您的示例,您实际上根本不需要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 回答