1

I have 3 functions, kk expect Array[Byte] or List[Array[Byte]], So I did a pattern matching,

def gg (a :Array[Byte]) = "w"
def ff (a :List[Array[Byte]]) = "f"

def kk(datum : Any) = datum match {
  case w : Array[Byte] => gg(w)
  case f :List[Array[Byte]] => ff(f)
  case _ => throw new Exception("bad data")
}

and I get an error when I try to compile the code:

non-variable type argument List[Any] in type pattern List[List[Any]] (the underlying of List[List[Any]]) is unchecked since it is eliminated by erasure

so instead I construct my kk function as flowing and it can be compiled now:

def kk(datum : Any) = datum match {
  case w : Array[Byte] => gg(w)
  case f :List[_] => ff(f.asInstanceOf[List[Array[Byte]]])
  case _ => throw new Exception("bad data")}

My questions: 1: is my current version of kk is idiomatic way to do a pattern matching for List, if not can someone show to how to do it?

2: say if I want to pattern matching List[Any] and List[List[Any]], how am able to do that? (ff(f.asInstanceOf[List[Array[Byte]]]) may cause an error if I datum is type of List[Byte])

rogerdeuce
  • 1,471
  • 6
  • 31
  • 48
EdwinGuo
  • 1,765
  • 2
  • 21
  • 27
  • Thanks for you post, I think http://stackoverflow.com/questions/12218641/scala-what-is-a-typetag-and-how-do-i-use-it would be an good place as well. – EdwinGuo May 22 '15 at 18:44
  • after reading, the new code should be looks like: def gg (a :Array[Byte]) = "w" def ff (a :List[Array[Byte]]) = "f" def binaryDecodexx[A : TypeTag](datum : A) = typeOf[A] match { case t if t =:= typeOf[Array[Byte]] => gg(datum.asInstanceOf[Array[Byte]]) case t if t =:= typeOf[List[Array[Byte]]] => ff(datum.asInstanceOf[List[Array[Byte]]]) // case w : Array[Byte] => gg(w) // case f :List[_] => } – EdwinGuo May 22 '15 at 18:45

1 Answers1

1

There is several things to be said:

  1. Type erasure is sometimes heavy thing to deal with. Try to gain your insight in this question
  2. Need for function like that is probably caused by bad design somewhere else. T and List[T] are rarely used as alternatives. If it is your case, try bring them to at least Either's or more specific case classes.
  3. If you are really have Any without any other prearranged knowledge and you really have the need of certainty it's List[Byte] or List[List[Byte]] your only option is to check every element of collection like this:

    class ListMatch[A](f: Any => Option[A]) {
      def unapply(obj: Any) = obj match {
        case seq: List[_] =>
          seq.foldLeft[Option[List[A]]](Some(Nil)) {
            (optSeq, elem) => for {
              seq <- optSeq
              elem <- f(elem)
            } yield elem :: seq
          } map (_.reverse)
        case _ => None
      }
    }
    
    val matchByte: PartialFunction[Any, Byte] = {
      case b: Byte => b
    }
    
    val ByteList = new ListMatch(matchByte.lift)
    val ByteListList = new ListMatch(ByteList.unapply)
    

    so you definition changes to

    def kk(datum: Any) = datum match {
      case ByteList(w) => gg(w)
      case ByteListList(f) => ff(f)
      case _ => "bad data"
    }
    

    you could try following tests to ensure correctness:

    kk(1)  // bad data
    kk(List(1.toByte)) // w
    kk(List(List(1.toByte))) // f
    kk(List(1.toByte, 2)) // bad data
    kk(List(1.toByte), List(2)) // bad data
    
Community
  • 1
  • 1
Odomontois
  • 15,918
  • 2
  • 36
  • 71