- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
Array[T] in function with type parameter T
Tue, 2012-02-07, 04:08
Hi,
why does the following function declaration yield an error?
def dummyfunction[T<:AnyRef](x:T) {
var dummyArray: Array[T] = Array(x)
}
(Raplacing "Array" by "List" eliminates the error.)
Thanks,
HjP
Wed, 2012-02-08, 12:01
#2
Help neeed: flatten nested tuples
Hi
I need to flatten nested tuples with elements of kind (1, ((2, 3), 4)) (always Tuple2!).
I got quite far using a naive binary tree:
sealed trait NT[+X <: AnyVal]
case class E[+X <: AnyVal](x: X) extends NT[X]
case class T[+X <: AnyVal](_1: NT[X], _2: NT[X]) extends NT[X]
def fltn[X <: AnyVal](nTpl: NT[X]): List[X] = nTpl match {
case T(_1, _2) => fltn(_1) ::: fltn(_2)
case E(x) => List(x)
}
implicit def toNT[X <: AnyVal](a: Any): NT[X] = a match {
case (x, y) => T(x, y)
case x: X => E(x)
}
Ignoring for a moment the warning "abstract type X in type pattern X is unchecked since it is eliminated by erasure case x: X => E(x)" (quite likely part of the problem) it is not so bad:
scala> fltn[Int]((1, ((2, 3), 4)))
res1: List[Int] = List(1, 2, 3, 4)
But it should be possible to do better:
1) fltn needs help: fltn((1, ((2, 3), 4))) gives List[Nothing], how to avoid this?
2) how to use view bounds, means fltn((1, ((2.0, 3), 4))) should give List[Double], currently without type help I get List[Nothing], but even when I do
scala> fltn[Double]((1, ((2, 3.0), 4)))
res3: List[Double] = List(1, 2, 3.0, 4)
which is as the rhs indicates crap already, because res3.head gives
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Double ...
Any idea how to improve?
Thanks a lot, Volker.
Wed, 2012-02-08, 13:41
#3
Re: Help neeed: flatten nested tuples
On Wed, Feb 8, 2012 at 10:56 AM, Bardenhorst, Volker Dr.
wrote:
> Hi
>
> I need to flatten nested tuples with elements of kind (1, ((2, 3), 4)) (always Tuple2!).
>
> I got quite far using a naive binary tree:
>
> sealed trait NT[+X <: AnyVal]
> case class E[+X <: AnyVal](x: X) extends NT[X]
> case class T[+X <: AnyVal](_1: NT[X], _2: NT[X]) extends NT[X]
>
> def fltn[X <: AnyVal](nTpl: NT[X]): List[X] = nTpl match {
> case T(_1, _2) => fltn(_1) ::: fltn(_2)
> case E(x) => List(x)
> }
>
> implicit def toNT[X <: AnyVal](a: Any): NT[X] = a match {
> case (x, y) => T(x, y)
> case x: X => E(x)
> }
>
> Ignoring for a moment the warning "abstract type X in type pattern X is unchecked since it is eliminated by erasure case x: X => E(x)" (quite likely part of the problem) it is not so bad:
>
> scala> fltn[Int]((1, ((2, 3), 4)))
> res1: List[Int] = List(1, 2, 3, 4)
>
> But it should be possible to do better:
>
> 1) fltn needs help: fltn((1, ((2, 3), 4))) gives List[Nothing], how to avoid this?
>
> 2) how to use view bounds, means fltn((1, ((2.0, 3), 4))) should give List[Double], currently without type help I get List[Nothing], but even when I do
>
> scala> fltn[Double]((1, ((2, 3.0), 4)))
> res3: List[Double] = List(1, 2, 3.0, 4)
>
> which is as the rhs indicates crap already, because res3.head gives
>
> java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Double ...
>
> Any idea how to improve?
>
> Thanks a lot, Volker.
That's a fantastic non-trival example for shapeless ... thanks! :-)
I've just pushed a solution here,
and will incorporate some of the infrastructure into the main library
later. From a usage point of view the code looks exactly how you want
it to (although from an implementation point of view there's a lot of
heavy lifting going on in the background),
val t1 = (1, ((2, 3), 4))
val f1 = flatten(t1) // Inferred type is Int :: Int :: Int :: Int :: HNil
val l1 = f1.toList // Inferred type is List[Int]
val t2 = (1, ((2, 3.0), 4))
val f2 = flatten(t2) // Inferred type is Int :: Int :: Double ::
Int :: HNil
val ds = f2 map toDouble // Inferred type is Double :: Double ::
Double :: Double :: HNil
val l2 = ds.toList // Inferred type is List[Double]
Note that this is quite a bit more general than you asked for. For
example we can flatten nested tuples of arbitrary arities and with
arbitrary element types,
val t3 = (23, ((true, 2.0, "foo"), "bar"), (13, false))
val f3 = flatten(t3) // Inferred type is Int :: Boolean ::
Double :: String :: String :: Int :: Boolean :: HNil
val t3b = f3.tupled // Inferred type is (Int, Boolean, Double,
String, String, Int, Boolean)
I'd love to know what your application for this is ...
Cheers,
Miles
Wed, 2012-02-08, 13:51
#4
Re: Help neeed: flatten nested tuples
On 2012-02-08 11:56, Bardenhorst, Volker Dr. wrote:
> I need to flatten nested tuples with elements of kind (1, ((2, 3), 4)) (always Tuple2!).
> 1) fltn needs help: fltn((1, ((2, 3), 4))) gives List[Nothing], how to avoid this?
>
> 2) how to use view bounds, means fltn((1, ((2.0, 3), 4))) should give List[Double], currently without type help I get List[Nothing], but even when I do
>
> scala> fltn[Double]((1, ((2, 3.0), 4)))
> res3: List[Double] = List(1, 2, 3.0, 4)
Functional dependencies to the rescue:
trait Flatten[T, R] extends (T => List[R])
object Flatten {
implicit def flattenTuple2[T1, T2, R](implicit f1: Flatten[T1, _ <:
R], f2: Flatten[T2, _ <: R]): Flatten[(T1, T2), R] = new Flatten[(T1,
T2), R] {
def apply(value: (T1, T2)): List[R] = f1(value._1) ::: f2(value._2)
}
implicit def flattenAnything[T <: AnyVal, R](implicit f: (T => R)):
Flatten[T, R] = new Flatten[T, R] {
def apply(value: T) = List(f(value))
}
}
def flatten[R] = new {
def apply[T](v: T)(implicit f: Flatten[T, R]): List[R] = f(v)
}
Types can be inferred when the tuples are uniformly typed:
flatten((1, ((2, 3), 4)))
I couldn't get type unification or implicit conversions to be inferred
automatically but it works if you annotate it with the desired result type:
flatten[Double]((1, ((2, 3.0), 4)))
Cheers,
Stefan
Wed, 2012-02-08, 16:51
#5
RE: Help neeed: flatten nested tuples
Hi Stefan, Klaus,
both replies did the job. Thanks you very much.
Klaus: you created that on the fly or did you adapt an older use case?
Miles: I created my own collection TimeSeries (~TreeMap). Currently I didn't set up a type safe DataTable. In the mean time to deal with multi columen data I added a zip to TimeSeries zipping corresponding time stamps like that
(t -> x) zip (t -> y) gives (t -> (x, y))
Repeating that the values can pump up to nested tuples. My problem was linked to the use case to do operations on those nested tuples.
Take care, Volker.
-----Original Message-----
From: scala-user@googlegroups.com [mailto:scala-user@googlegroups.com] On Behalf Of Stefan Zeiger
Sent: 08 February 2012 13:39
To: scala-user@googlegroups.com
Subject: Re: [scala-user] Help neeed: flatten nested tuples
On 2012-02-08 11:56, Bardenhorst, Volker Dr. wrote:
> I need to flatten nested tuples with elements of kind (1, ((2, 3), 4)) (always Tuple2!).
> 1) fltn needs help: fltn((1, ((2, 3), 4))) gives List[Nothing], how to avoid this?
>
> 2) how to use view bounds, means fltn((1, ((2.0, 3), 4))) should give
> List[Double], currently without type help I get List[Nothing], but
> even when I do
>
> scala> fltn[Double]((1, ((2, 3.0), 4)))
> res3: List[Double] = List(1, 2, 3.0, 4)
Functional dependencies to the rescue:
trait Flatten[T, R] extends (T => List[R])
object Flatten {
implicit def flattenTuple2[T1, T2, R](implicit f1: Flatten[T1, _ <:
R], f2: Flatten[T2, _ <: R]): Flatten[(T1, T2), R] = new Flatten[(T1, T2), R] {
def apply(value: (T1, T2)): List[R] = f1(value._1) ::: f2(value._2)
}
implicit def flattenAnything[T <: AnyVal, R](implicit f: (T => R)):
Flatten[T, R] = new Flatten[T, R] {
def apply(value: T) = List(f(value))
}
}
def flatten[R] = new {
def apply[T](v: T)(implicit f: Flatten[T, R]): List[R] = f(v)
}
Types can be inferred when the tuples are uniformly typed:
flatten((1, ((2, 3), 4)))
I couldn't get type unification or implicit conversions to be inferred automatically but it works if you annotate it with the desired result type:
flatten[Double]((1, ((2, 3.0), 4)))
Cheers,
Stefan
On Mon, Feb 06, 2012 at 07:07:47PM -0800, HjP wrote:
> why does the following function declaration yield an error?
>
> def dummyfunction[T<:AnyRef](x:T) {
> var dummyArray: Array[T] = Array(x)
> }
Did you Google the error you got? The "Array" type is special (since it
maps to types like Object[] and int[] on the JVM). To create a new
array with a generic type requires a Manifest.
def tryMe[T<:AnyRef:Manifest](x:T) = Array(x)