Reputation: 15093
I would like to pattern match
on different segments of a list
in scala
on the types of the head
and tail
:
class Solution07 extends FlatSpec with ShouldMatchers {
"plain recursive flatten" should "flatten a list" in {
val list1 = List(List(1, 1), 2, List(3, List(5, 8)))
val list1Flattened = List(1, 1, 2, 3, 5, 8)
flattenRecur(list1) should be (list1Flattened)
}
def flattenRecur(ls: List[Any]): List[Int] = ls match {
case (head: Int) :: (tail: List[Any]) => head :: flattenRecur(tail)
case (head: List[Int]) :: (tail: List[Any]) => head.head :: flattenRecur(head.tail :: tail)
case (head: List[Any]) :: (tail: List[Any]) => flattenRecur(head) :: flattenRecur(tail) // non-variable type... on this line.
}
}
I get:
Error:(18, 17) non-variable type argument Int in type pattern List[Int] (the underlying of List[Int]) is unchecked since it is eliminated by erasure case (head: List[Int]) :: (tail: List[Any]) => head.head :: flattenRecur(head.tail :: tail) ^
What am I missing? how is it possible for me to pattern match on the head
and tail
's types of the list?
Upvotes: 8
Views: 15743
Reputation: 10884
You are hit by restrictions given by the object system:
The only common parent for List[Int]
and Int
is Any
So due to that the inference system can only safely assume that you could return Any
. The solution proposed @jwvh is doable but has a possible danger of runtime exceptions.
If you want to solve the problem in a typesafe way an option could be to use HList
of the shapeless library https://github.com/milessabin/shapeless : https://github.com/milessabin/shapeless/wiki/Feature-overview:-shapeless-2.0.0#heterogenous-lists
Upvotes: 1
Reputation: 8462
I agree that @Andreas solution with HList is a nice example for solving the problem, but I still do not understand what's the problem with this:
def flatten(ls: List[_]): List[Int] = ls match {
case Nil => Nil
case (a: Int) :: tail => a :: flatten(tail)
case (a: List[_]) :: tail => flatten(a) ::: flatten(tail)
case _ :: tail => flatten(tail)
}
Then:
println(flatten(List(List("one",9,8),3,"str",4,List(true,77,3.2)))) // List(9, 8, 3, 4, 77)
I don't see any problems with type erasure in your task, because you actually don't need to test the types that are erased. I've intentionally skipped all erased types in my example - to show this. Type erasure does not clear the type information of the elements of the list, it clears only the type information of list generic which you have Any
or _
in my case - so you do not need that at all. If I am not missing someting, in your example the types are not erased at all, because you anyway have Any
almost everywhere.
Upvotes: 11