- 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 [at] googlegroups [dot] com [mailto:scala-user [at] googlegroups [dot] com] On Behalf Of Stefan Zeiger

Sent: 08 February 2012 13:39

To: scala-user [at] googlegroups [dot] 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)