Lets say I have a function f: A => A, A being any kind of object. And
I have a Collection containing heterogeneous data, including A and
also Collection of Collection and so on.
If I want to use it with an Int, I can write things as:
scala> def testi(a:Any, f:Int => Int):Any = a match {
| case a:Int => f(a)
| case a:List[_] => a.map(testi(_,f))
| case _ => a
| }
Then I create a function:
scala> def f(x:Int):Int = x+1
f: (x: Int)Int
If i do:
testi(10,f) I get 11
test("aaa",f), I get aaa
testi(List(1,2,"a",List("b",3,4)), I get List(2,3,a,List(b,4,5))
Fine lets say now, I want to do the same with f:String => String, this
is very similar and I would like something generic like:
scala> def test[A](a:Any, f:A => A):Any = a match {
| case a:A => f(a)
| case a:List[_] => a.map(test[A](_,f))
| case _ => a
| }
Unfortunately that does not work. I can have this working but with
homogeneous List. But I am not satisfied with the way I did:
scala> def test[A](a:Any, f:A => A):Any = a match {
| case a:List[_] => a.map(test[A](_,f))
| case a:A => f(a)
| }
Reading some posts on the Net, I was able to find some suggestions
with implicit variable related to Manifest but was not able to solve
totally the problem. I tried something like and variants:
scala> def test[A](a:Any, f:A => A)(implicit m:Manifest[A]):Any = a
match {
| case a:A if m.erasure == a.asInstanceOf[AnyRef].getClass =>
f(a)
| case a:List[_] => a.map(test[A](_,f))
| case _ => a
| }
Can anyone suggest a clean way to solve this problem ?
Thanks in advance.
Regards
-------- Original-Nachricht --------
> Datum: Tue, 13 Dec 2011 07:03:29 -0800 (PST)
> Von: Pascal <pasc...@gmail.com>
> An: scala-user <scala...@googlegroups.com>
> Betreff: [scala-user] Scala with Generics in pattern matching - issue with erasing
You want a function g that receives either A, List[A],List[List[A]],
List[List[List[A]]], or any other type as the first parameter.
The second parameter is f:A=>A.
The function g returns:
1) f(x) when it receives x:A.
2) xs.map(f) , or xss.map(_.map(f)), or ...., when it receives
xs:List[A], xss.List[List[A]], xsss:List[List[List[A]]] ,...
3) y when it receives y:Any .
The problem is how to encode List[A], List[List[A]],
List[List[List[A]]],...
Anybody ?
Anwar.
Let me see the question from another angle: how to encode a recursive type.
A combination of implicits and default arguments works:case class Flat[T, U](fn: T => List[U])implicit def recFlattenFn[T, U](implicit f: Flat[T, U] = Flat((l: T) => List(l))) =Flat((l: List[T]) => l.flatMap(f.fn))def recFlatten[T, U](l: List[T])(implicit f: Flat[List[T], U]) =f.fn(l)Examples:scala> recFlatten(List(1, 2, 3))res0: List[Int] = List(1, 2, 3)scala> recFlatten(List(List(1, 2, 3), List(4, 5)))res1: List[Int] = List(1, 2, 3, 4, 5)scala> recFlatten(List(List(List(1, 2, 3),List(4, 5)), List(List(6, 7))))res2: List[Int] = List(1, 2, 3, 4, 5, 6, 7)