简体   繁体   中英

pattern matching function signatures with ClassTags/TypeTags

I have a method that explores different parameter values for different classes of functions. Previously, I did some un-typesafe runtime checks, where, post-erasure, all that mattered was that I was using a Function2 versus a Function3. I've taking a stab at using ClassTags/TypeTags to be a bit safer, but I'm still struggling for a good solution. My original reference point was tksfz's answer to:

How do I get around type erasure on Scala? Or, why can't I get the type parameter of my collections?

import reflect.ClassTag
def matchList[A: ClassTag](list: List[A]) = list match {
  case strlist: List[String] => println("A list of strings!")
  case intlist: List[Int] => println("A list of ints!")
  case _ => println("Ok")
}

However, I found that the snippet as given didn't work, and both cases match a list of strings -- it may be that the answer concerns a different version of scala (I'm using 2.10.3).

I found another example, in which someone gave a snippet using TypeTags (and I'm still a bit hazy on what the difference is between the type tag types; I'd be happy for an RTFM response on that point, provided it's accompanied by a link to a good M to FR).

EDIT : My earlier example didn't apply the functions, so the parts of the matching that produced warnings were pointless (as the first answerer pointed out). I've updated the example so that it's more representative of my actual problem.

package misc
import reflect.runtime.universe._

object CTDemo {

  def main(args: Array[String]) = {
    val f0v: Function2[Int, Double, String] = f0(_, _)
    val f1v: Function2[Int, (Double, Double), String] = f1(_, _)
    println(matchFunc(f0v))
    println(matchFunc(f1v))
  }

  def f0(i: Int, p: Double) = {
    s"output on $p doesn't matter"
  }

  def f1(i: Int, p: (Double, Double)) = {
    s"output on $p doesn't matter"
  }

  def matchFunc[I: TypeTag, A: TypeTag, O: TypeTag](predFunc: Function2[I, A, O]) = {
    predFunc match {
      case fs: Function2[Int, Double, String] if(typeOf[A] <:< typeOf[Double]) => {
        "Single-arg, result is: " + fs(1,2.0)
      }
      case ds: Function2[Int, (Double, Double), String] if(typeOf[A] <:< typeOf[(Double,Double)])  => {
        "Double-arg, result is: " + ds(1,(2.0,3.0))
      }
    }
  }
}

This case works, but it still throws compiler warnings. Is there a succinct, "asInstanceOf"-free, warning-free, and thread-safe way to check the type signature of functions? I'm willing to upgrade to scala 2.11 if that would help.

Your matches aren't doing any work, so just

  def matchFunc[I: TypeTag, A: TypeTag, O: TypeTag](predFunc: Function2[I, A, O]) = {
      if (typeOf[A] <:< typeOf[Double]) {
        "Single-arg"
      } else if (typeOf[A] <:< typeOf[(Double,Double)]) {
        "Double-arg"
      }
  }

The other idiom works thisaway:

scala> def g[A: reflect.ClassTag](as: List[A]) = as match { case List(_: Int) => "I" }
g: [A](as: List[A])(implicit evidence$1: scala.reflect.ClassTag[A])String

scala> g(List(3))
res4: String = I

scala> g(List(3.0))
scala.MatchError: List(3.0) (of class scala.collection.immutable.$colon$colon)
  at .g(<console>:7)
  ... 33 elided

That is, as a glorified (albeit convenient) isInstanceOf.

In Scala, it's RTFS, where S = spec or SIP.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM