scala multi dimensional array representation in repl - scala

I am new to scala and I wrote this in repl
val xx = Array.ofDim [String](3,4)
xx: Array[Array[String]] = Array(Array(null, null, null, null), Array(null, null,
null, null), Array(null, null, null, null))
# val yy = Array.ofDim [Int](3,4)
yy: Array[Array[Int]] = Array(Array(0, 0, 0, 0), Array(0, 0, 0, 0), Array(0, 0, 0, 0))
# val ss = Array(xx, yy)
which resulted in this
ss: Array[Array[_1] forSome { type _1 >: Array[Int] with Array[String] <: Array[_1] forSome { type _1 >: Int with String } }] = Array(
Array(Array(null, null, null, null), Array(null, null, null, null), Array(null, null, null, null)),
Array(Array(0, 0, 0, 0), Array(0, 0, 0, 0), Array(0, 0, 0, 0))
)
can someone please explain what does this mean
Array[_1] forSome { type _1 >: Array[Int] with Array[String] <: Array[_1] forSome { type _1 >: Int with String } }
specially the >: .....<: .... part.
by the way I am using scala 2.13.
cheers,
es

The forSome keyword in Scala creates an existential type. That is a type that you don't know or don't care what it precisely is, you can just provide conditions for it. More in this answer.
The <: and :> operators mean type bound. A definition like type A <: B means, that type A is a subtype of B. And the definition type A >: B means that A is a supertype of B.
In this case (last snippet), it means that you have an Array with a parameter _1 about which we know that it is a supertype of Array[Int] with Array[String] and a subtype of Array[_1] forSome { type _1 >: Int with String }

Related

Scala: Why the Int type list contains String as well?

val wordList = List("I", "want", "to", "learn", "scala")
val wordSizeList = list.map(x=>x.length)
def func[A, B](a:List[A]):List[B]={
a.collect({case x:B => x})
}
val result = func[Any, Int](wordList ::: wordSizeList)
Below is the worksheet result
wordList: List[String] = List(I, want, to, learn, scala)
wordSizeList: List[Int] = List(1, 4, 2, 5, 5)
func: [A, B](a: List[A])List[B]
result: List[Int] = List(I, want, to, learn, scala, 1, 4, 2, 5, 5)
why doesn't it filter based on the Generic type "B"?
And if you see the result list, how can a Int type list can contain String as well?
Looks to me a type erasure problem, which can be remedied with a ClassTag:
import scala.reflect.ClassTag
def func[A, B : ClassTag](a: List[A]): List[B] = {
a.collect{ case x: B => x }
}
val result = func[Any, Int](wordList ::: wordSizeList)
// result: List[Int] = List(1, 4, 2, 5, 5)

Getting proper type constructor parameters for a "refined" type

I'm having problems comparing the 'compatibility' between two types using reflection (actually I'm writing a macro). For example, I want to permit Vector[Int] === List[Int]. Now I know the general approach. But the problem is I cannot get the type constructor parameters in this case:
import scala.reflect._
import runtime.universe._
typeOf[List[Int]].typeArgs // List(Int) OK
typeOf[List[Int] with java.io.Serializable].typeArgs // List() FAIL
Why is this a problem?
def test[A, B >: A](a: A, b: B)(implicit tt: TypeTag[B]) = {
println(s"tt = $tt")
typeOf[B].typeArgs
}
Now this works:
test(List(1, 2, 3), List(1, 2, 3)) // List(Int)
But this doesn't:
test(Vector(1, 2, 3), List(1, 2, 3)) // List()
One can use an extractor called RefinedType:
def test[A, B >: A](a: A, b: B)(implicit tt: TypeTag[B]): List[List[Type]] = {
val all = typeOf[B] match {
case RefinedType(parents, scope) => parents.map(_.typeArgs)
case x => x.typeArgs :: Nil
}
all.filter(_.nonEmpty)
}
test(List(1, 2, 3), List(1, 2, 3))
test(Vector(1, 2, 3), List(1, 2, 3))
Then one still has to somehow find a strategy to align the parents. (I'm testing all combinations now).

Scala collect items of a type from a collection

Consider an Array[Any]
val a = Array(1,2,"a")
a: Array[Any] = Array(1, 2, a)
We can collect all the items of type Int like this,
a.collect { case v: Int => v }
res: Array[Int] = Array(1, 2)
Though how to define a function that collects items of a given type, having unsuccessfully tried this,
def co[T](a: Array[Any]) = a.collect { case v: T => v }
warning: abstract type pattern T is unchecked since it is eliminated by erasure
which delivers
co[Int](a)
ArraySeq(1, 2, a)
co[String](a)
ArraySeq(1, 2, a)
You need to provide a ClassTag for the pattern match to actually work:
import scala.reflect.ClassTag
def co[T: ClassTag](a: Array[Any]) = a.collect { case v: T => v }

Update multiple values in a sequence

To get a sequence with one value updated, one can use
seq.updated(index, value)
I want to set a new value for a range of elements. Is there a library function for that? I currently use the following function:
def updatedSlice[A](seq: List[A], ind: Iterable[Int], value: A): List[A] =
if (ind.isEmpty) seq
else updatedSlice(seq.updated(ind.head, value), ind.tail, value)
Besides the need of writing function, this seems to be inefficient, and also works only for lists, rather than arbitrary subclasses of Seq and Strings. So,
is there a method that performs it?
how can I parametrize the function to take (and return) some subclass of Seq[A]?
To my knowledge there's no combinator that directly provides this functionality.
For the Seq part, well, it works only for List because you're taking a List as a parameter. Take a Seq, return a Seq and you already have one less problem.
Moreover, your implementation throws an IndexOutOfBounds exception if ind contains an index greater or equal to the seq length.
Here's an alternative implementation (which uses Set for a O(1) contains)
def updatedAtIndexes[A](seq: Seq[A], ind: Set[Int], value: A): Seq[A] = seq.zipWithIndex.map {
case (el, i) if ind.contains(i) => value
case (el, _) => el
}
Example
updatedAtIndexes(List(1, 2, 3, 4, 5), Set(0, 2), 42) // List(42, 2, 42, 4)
You can even make it prettier with a simple implicit class:
implicit class MyPimpedSeq[A](seq: Seq[A]) {
def updatedAtIndexes(ind: Set[Int], value: A): Seq[A] = seq.zipWithIndex.map {
case (el, i) if ind.contains(i) => value
case (el, _) => el
}
}
Examples
List(1, 2, 3, 4).updatedAtIndexes(Set(0, 2), 42) // List(42, 2, 42, 4)
Vector(1, 2, 3).updatedAtIndexes(Set(1, 2, 3), 42) // Vector(1, 42, 42)
No one at a computer has said:
scala> (1 to 10).toSeq patch (3, (1 to 5), 3)
res0: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3, 1, 2, 3, 4, 5, 7, 8, 9, 10)
Save your green checks for #Marth.
Note they're still working on it.
https://issues.scala-lang.org/browse/SI-8474
Which says something about less-frequently-used API.
Update: I glanced at the question a second time and saw that I misread it, oh well:
scala> implicit class x[A](as: Seq[A]) {
| def updatedAt(is: collection.Traversable[Int], a: A) = {
| (as /: is) { case (xx, i) => xx updated (i, a) } } }
defined class x
scala> (1 to 10) updatedAt (Seq(3,6,9), 0)
res9: Seq[Int] = Vector(1, 2, 3, 0, 5, 6, 0, 8, 9, 0)
Just a relaxing round of golf.
Update: s/relaxing/annoying
Looks like it needs more type params, but I don't have a time slice for it.
scala> implicit class slicer[A, B[_] <: Seq[_]](as: B[A]) {
| def updatedAt[That<:B[_]](is: Traversable[Int], a: A)(implicit cbf: CanBuildFrom[B[A], A, That]) =
| (as /: is) { case (x,i) => x updated[A,That] (i,a) }}
<console>:15: error: type arguments [A,That] conform to the bounds of none of the overloaded alternatives of
value updated: [B >: _$1, That](index: Int, elem: B)(implicit bf: scala.collection.generic.CanBuildFrom[Seq[_$1],B,That])That <and> [B >: A, That](index: Int, elem: B)(implicit bf: scala.collection.generic.CanBuildFrom[Repr,B,That])That
(as /: is) { case (x,i) => x updated[A,That] (i,a) }}
^
Who even knew updated was overloaded?
My new favorite Odersky quote:
I played with it until it got too tedious.

Working with tuples in Scala

I want to do something like this (simplified quite heavily):
((1, 2, 3, 4, 5, 6), (6, 5, 4, 3, 2, 1)).zipped map (_ + _)
Ignore the actual values of the integers (although it's important that these are 6-tuples, actually :)). Essentially, I want to use this fairly regularly in a function which maintains a Map[String, (Int, Int, Int, Int, Int, Int)] when an existing element is updated.
As it is, Scala spits this out at me:
<console>:6: error: could not find implicit value for parameter w1: ((Int, Int, Int, Int, Int, Int)) => scala.collection.TraversableLike[El1,Repr1]
((1, 2, 3, 4, 5, 6), (6, 5, 4, 3, 2, 1)).zipped
If I use Seqs instead of tuples, everything works fine, but I want to enforce an arity of 6 in the type system (I'll probably type Record = (Int, Int, Int, Int, Int, Int) as a quick refactor shortly).
Can anyone offer some advice on what I'm doing wrong/why Scala won't deal with the code above? I thought it might work if I used a 2- or 3-arity tuple, seeing as Scala defines Tuple2 and Tuple3s (I understand that scaling tuple functions across an arbitrary n-arity is difficult), but I get the same error.
Thanks in advance for any help offered :).
You only want to map over tuples which have identical types--otherwise the map wouldn't make sense--but Tuple doesn't contain that in its type signature. But if you're willing to do a little work, you can set it up so that tuples work the way you requested:
Groundwork:
class TupTup6[A,B](a: (A,A,A,A,A,A), b: (B,B,B,B,B,B)) {
def op[C](f:(A,B)=>C) = ( f(a._1,b._1), f(a._2,b._2), f(a._3,b._3),
f(a._4,b._4), f(a._5,b._5), f(a._6,b._6) )
}
implicit def enable_tuptup6[A,B](ab: ((A,A,A,A,A,A),(B,B,B,B,B,B))) = {
new TupTup6(ab._1,ab._2)
}
Usage:
scala> ((1,2,3,4,5,6) , (6,5,4,3,2,1)) op { _ + _ }
res0: (Int, Int, Int, Int, Int, Int) = (7,7,7,7,7,7)
I received this little inspiration.
class TupleZipper[T <: Product](t1: T) {
private def listify(p: Product) = p.productIterator.toList
def zipWith(t2: T) = (listify(t1), listify(t2)).zipped
}
implicit def mkZipper[T <: Product](t1: T) = new TupleZipper(t1)
// ha ha, it's arity magic
scala> ((1, 2, 3, 4, 5, 6)) zipWith ((6, 5, 4, 3, 2))
<console>:8: error: type mismatch;
found : (Int, Int, Int, Int, Int)
required: (Int, Int, Int, Int, Int, Int)
((1, 2, 3, 4, 5, 6)) zipWith ((6, 5, 4, 3, 2))
^
scala> ((1, 2, 3, 4, 5, 6)) zipWith ((6, 5, 4, 3, 2, 1))
res1: (List[Any], List[Any])#Zipped[List[Any],Any,List[Any],Any] = scala.Tuple2$Zipped#42e934e
scala> res1 map ((x, y) => x.asInstanceOf[Int] + y.asInstanceOf[Int])
res2: List[Int] = List(7, 7, 7, 7, 7, 7)
Yes, a bunch of Anys comes out the other end. Not real thrilling but not a lot you can do when you try to force yourself on Tuples this way.
Edit: oh, and of course the type system gives you the full monty here.
scala> ((1, 2, 3, 4, 5, 6)) zipWith ((6, 5, 4, 3, 2, "abc"))
<console>:8: error: type mismatch;
found : java.lang.String("abc")
required: Int
((1, 2, 3, 4, 5, 6)) zipWith ((6, 5, 4, 3, 2, "abc"))
^
import scala.collection._
type Record = (Int, Int, Int, Int, Int, Int)
implicit def toIterable(r: Record) = new Iterable[Int]{
def iterator = r.productIterator.asInstanceOf[Iterator[Int]]
}
implicit def cbf[From <: Iterable[Int]] = new generic.CanBuildFrom[From, Int, Record] {
def apply(from: From) = apply
def apply = new mutable.Builder[Int, Record] {
var array = Array.ofDim[Int](6)
var i = 0
def +=(elem: Int) = {
array(i) += elem
i += 1
this
}
def clear() = i = 0
def result() = (array(0), array(1), array(2), array(3), array(4), array(5))
}
}
usage:
scala> ((1, 2, 3, 4, 5, 6), (6, 5, 4, 3, 2, 1)).zipped.map{_ + _}
res1: (Int, Int, Int, Int, Int, Int) = (7,7,7,7,7,7)
Tuple2#zipped won't help you out here, it works when the contained elements are TraversableLike/IterableLike - which Tuples aren't.
You'll probably want to define your own sumRecords function that takes two Records and returns their sum:
def sumRecord(a:Record, b:Record) = new Record(
a._1 + b._1,
a._2 + b._2,
a._3 + b._3,
a._4 + b._4,
a._5 + b._5,
a._6 + b._6
)
Then to use it with a Pair[Record, Record]:
val p : Pair[Record, Record] = ...
val summed = sumRecord(p._1, p._2)
Sure, there are abstractions available; but as Record is going to be fixed throughout your design, then they have little value.
short solution:
type Record = (Int, Int, Int, Int, Int, Int)
implicit def toList(r: Record) = r.productIterator.asInstanceOf[Iterator[Int]].toList
implicit def toTuple(l: List[Int]): Record = (l(0), l(1), l(2), l(3), l(4), l(5))
usage:
scala> ((1,2,3,4,5,6), (6,5,4,3,2,1)).zipped map {_ + _}: Record
res0: (Int, Int, Int, Int, Int, Int) = (7,7,7,7,7,7)
You can now easily achieve this with shapeless, this way:
import shapeless._
import shapeless.syntax.std.tuple._
val a = (1, 2, 3, 4, 5, 6)
val b = (6, 5, 4, 3, 2, 1)
object sum extends Poly1 {
implicit def f = use((t: (Int, Int)) => t._1 + t._2)
}
val r = a.zip(b) map sum // r is a (Int, Int, Int, Int, Int, Int)
The drawback is the weird syntax you have to use to express the sum function, but everything is type-safe and type-checked.
As update to Rex Kerr answer, starting from Scala 2.10 you can use implicit classes: syntactic sugar that makes that solution even shorter.
implicit class TupTup6[A,B](x: ((A,A,A,A,A,A),(B,B,B,B,B,B))) {
def op[C](f:(A,B)=>C) = (
f(x._1._1,x._2._1),
f(x._1._2,x._2._2),
f(x._1._3,x._2._3),
f(x._1._4,x._2._4),
f(x._1._5,x._2._5),
f(x._1._6,x._2._6) )
}
You get the error because you treat the tuple as a collection.
Is it possible for you to use lists instead of tuples? Then the calculation is simple:
scala> List(1,2,3,4,5,6).zip(List(1,2,3,4,5,6)).map(x => x._1 + x._2 )
res6: List[Int] = List(2, 4, 6, 8, 10, 12)