How to match scala list header and tail style?

I would like a pattern match on different segments of a list in scala for head and tail types:

 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) argument of type non-variable Type Int in type List [Int] (base list List [Int]) is not marked, as it is eliminated by erasing case (head: List [Int]) :: (tail: List [Any]) => head.head :: flattenRecur (head.tail :: tail) ^

What am I missing? How can I match the pattern in the head and tail types of the list?

+5
source share
3 answers

I agree that @Andreas solution with HList is a good example to solve the problem, but I still don't understand what the problem is:

  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 see no problems with type erasure in your task, because you really don't need to check for erasable types. I intentionally skipped all erasable types in my example - to show this. The erasure type does not clear the information about the type of the list items, it only clears the information about the type of the generalized list that you have Any or _ in my case - so you don't need it at all. If I don’t miss anything, in your example the types will not be erased at all, because you still have Any almost everywhere.

+6
source

Due to type erasure, you can resort to checking each element.

 def flattenRecur(ls: List[Any]): List[Int] = ls match { case head :: tail if (head.isInstanceOf[Int]) => head.asInstanceOf[Int] :: flattenRecur(tail) case head :: tail if (head.isInstanceOf[List[Any]]) => flattenRecur(head.asInstanceOf[List[Any]]) ++ flattenRecur(tail) case _ :: tail => flattenRecur(tail) case _ => Nil } 

What works:

 scala> flattenRecur(List(List("one",9,8),3,"str",4,List(true,77,3.2))) res8: List[Int] = List(9, 8, 3, 4, 77) 

But generally, avoiding Any usually worth the effort.

+1
source

You are limited by the system of objects:

The only common parent for List[Int] and Int is Any

Therefore, because of this, the output system can only confidently assume that you can return Any . The solution suggested by @jwvh is doable, but there may be a risk of runtime exceptions.

If you want to solve the problem as a file, you can use the HList formless library https://github.com/milessabin/shapeless : https://github.com/milessabin/shapeless/wiki/Feature-overview:-shapeless-2.0.0 # heterogenous-lists

+1
source

Source: https://habr.com/ru/post/1237490/


All Articles