Obtaining array element in Scala works only with explicit apply method - arrays

Accessing collection elements in Scala is done by apply method. Having said that I tried to read numbers from standard input and get the second one as int in just one line.
def main(args: Array[String]): Unit = {
val number = StdIn.readLine().split(" ").map(_.toInt)(1)
}
IntelliJ marks this 1 and show the error (the same is shown after the compilation attempt):
Error:(11, 60) type mismatch; found : Int(1) required:
scala.collection.generic.CanBuildFrom[Array[String],Int,?]
val number = StdIn.readLine().split(" ").map(_.toInt)(1)
Folding the expression in the parentheses dosn't help as well. However, when I split mapping input to int array and getting the element to other lines, everything works fine.
def main(args: Array[String]): Unit = {
val numbers = StdIn.readLine().split(" ").map(_.toInt)
numbers(1)
}
The explicit invocation of apply also does the job:
val number = StdIn.readLine().split(" ").map(_.toInt).apply(1)
Why does this weird behaviour happens? Obtaining element via array(5) is just a shortcut for array.apply(5), isn't it?

As compiler already pointed out, map is defined with two arg lists. second one containing a single implicit param: implicit bf: CanBuildFrom[Repr, B, That]
For a vast majority of scenarios, the users don't worry about specifying the second arg. Specifically, in your case this is what the compiler "figures out":
StdIn.readLine().split(" ").map(_.toInt)(Array.canBuildFrom[Int])
So, if writing out apply is not desired then the following is the only choice:
StdIn.readLine().split(" ").map(_.toInt)(Array.canBuildFrom[Int])(1)
It's a bit counter-intuitive that adding a set of parentheses still doesn't quite do the trick:
( StdIn.readLine().split(" ").map(_.toInt) )(1) //does not compile, same error
Perhaps it's best to demonstrate what's going with a simpler example. Consider the following function:
def add(x:Int)(y:Int) = x + y
The type of add(2) is Int => Int (since we haven't specified y). Note that adding a set of parentheses around it doesn't change the return type, i.e. (add(2)) still has a type Int => Int. Similarly, (Array("1").map(_.toInt))(1) still requires an instance of CanBuildFrom before using shorthand for apply.
Suggested reading about Scala collections:
The Architecture of Scala Collections
Getting to know CanBuildFrom (without a PhD)
and implicit scope:
Scala Specification <- as comprehensive as it gets
Where does Scala look for implicits?

You're getting a collision with an implicit argument to map. This is one of the cases apply needs to be invoked explicitly.
Here's some REPL that replicates the error:
scala> class Foo {
def apply() { println("bar") }
}
scala> def makeFoo(): Foo = new Foo
scala> makeFoo()()
bar // got the println from the apply here
scala> def makeFooImplicit()(implicit x: Int): Foo = new Foo
scala> implicit val x = 5
scala> makeFooImplicit()()
<console>:11: error: not enough arguments for method makeFooImplicit:(implicit x: Int)Foo.
Unspecified value parameter x.
makeFooImplicit()()

Related

Scala overloading operators with generic types

I am doing a project in scala and i am struggling with a certain thing. I am making a matrix DSL so i am overloading some operators like +,- or * so that i can do :
matrixMult = matrix1*matrix2
The thing is i made this class where the matrix was represented as a Array[Array[Double]] type but i would like to make it generic: Array[Array[T]]
The thing is i do not know how to handle this in the class methods since for operations like +,- and *. It should work for doubles or ints, but strings should throw an error. Here is my current code:
def +(other : Matrix[Double]): Matrix[Double] = {
var array = new Array[Array[Double]](rows)
for (i <- 0 to (rows - 1)) {
var arrayRow = new Array[Double](columns)
for (j <- 0 to (columns - 1)) {
arrayRow(j) = this.array(i)(j) + other.array(i)(j)
}
array(i) = arrayRow
}
return new Matrix(array)
}
I get an error on the arrayRow(j) =... line which is normal because it does not know what type the "this" object is.
What should i do to make this work? Like i would like this method only to be accessible to doubles (or ints) and not strings, if this method was to be invoked on a Matrix[String] object it should throw an error. I tried pattern matching with isInstanceOf() but that doesn't remove the error and i can't compile.
If kind of have the same issue with all of my methods in my class, so i'd like a generic answer if possible.
Any help is appreciated,
Thank you very much!
Not sure which version of Scala you are using, but if you're on 2.8, I found this thread on Scala-lang, and it looks like you may be able to use T:Numerics to limit it to Int, Long, Float, Double.
A little farther down in the thread, to limit it to JUST a subset of those (like Int, Double), they say to define your own generic Trait.
https://www.scala-lang.org/old/node/4787
Answer can be found in comments:
Matrix addition has been asked, and answered, before. Even though the question posses a different matrix implementation, I believe the answer from the redoubtable Rex Kerr is still applicable. – jwvh

Checking whether an Array[A] is sorted?

While working through a problem found in 'Functional Programming in Scala':
Implement isSorted, which checks whether an Array[A] is sorted according to a given comparison function:
def isSorted[A](as: Array[A], ordered: (A,A) => Boolean): Boolean
While comparing my answer to the below solution provided by the author(s):
// Exercise 2: Implement a polymorphic function to check whether
// an `Array[A]` is sorted
def isSorted[A](as: Array[A], gt: (A,A) => Boolean): Boolean = {
#annotation.tailrec
def go(n: Int): Boolean =
if (n >= as.length-1) true
else if (gt(as(n), as(n+1))) false
else go(n+1)
go(0)
}
I am getting confused by the following line of code: else if (gt(as(n), as(n+1))) false
I thought when using a function as a parameter in Scala, one would need to actually define a separate function outside the scope of the current function (i.e. have another function defined that does what gt would need to do)? I don't see gt defined anywhere else, so how is it able to provide a Boolean value to use in isSorted?
Are my assumptions correct, or am I completely something missing here with using functions as parameters? A detailed explanation is much appreciated.
In this case, gt is a function passed to isSorted as an argument;
Let's compare it to any other argument, say a: Int. Let's look at the following function:
def increaseByOne(a: Int): Int = a + 1
Your question about gt is equivalent to asking: "How can increaseByOne use a if a is never assigned a value?". Obviously, the caller of the increaseByOne method would have to pass some value as the value of a, but the very concept of arguments is naming some value that is provided into the method.
The same goes for gt: it's an argument of isSorted. In the code you presented, we don't see the caller of isSorted, so we don't see any example of what gt might be - but obviously the implementation of isSorted need not assume anything about how and where gt is created, it is passed as an argument and therefore can be used in isSorted.
We can imagine a usage such as:
isSorted(Array(1,3,6), (a: Int, b: Int) => a > b)
Here, (a: Int, b: Int) => a > b would be the value of gt.

How can I specify a type for a function argument without restricting its dimensions?

In Julia, I want to specify the type of a function argument as an array of arrays. So I have
function foo{T <: Any}(x::Array{Array{T}})
but if I set the argument x in the REPL, for example:
x = Array[[0,1],[1,2,3],[0,1,2,4]]
then it automatically gets the following type assignment (for example), which includes its dimensions:
x::Array{Array{T,N},1}
so that I get the error
ERROR: `foo` has no method matching foo(::Array{Array{T,N},1}).
I don't want to restrict the array dimensions at all, so was thinking that the solution maybe something along the lines of
function foo{T <: Any, N <: Number}(x::Array{Array{T,N},N})
but this doesn't work either.
How can I specify the argument type to be an array of arrays?
Given an array of arrays x = Array[isodd(i) ? [1i,2i] : [1.0i 2.0i] for i=1:10], Julia reports its type as Array{Array{T,N},1}. This is deceiving, as it seems to imply that there exists some T and some N for which the above type will match. But that's not the case: the odd elements will be of type Array{Int,1}, and the evens are Array{Float64,2}. So when you try to write a method for foo with the type parameters:
foo{T,N}(::Array{Array{T,N},1}) = T,N
What are T and N for x? Clearly, there is no such N — it's both 1 and 2! And the elements of these subarrays aren't of type Any — they're both Int and Float64. The same applies for Array[[0,1],[0,1,2]], even though in your example you know that T and N are consistent, Julia's type system doesn'tâ€Ĥ and you could potentially push elements that aren't Int vectors.
There are quite a few ways around this. The best approach is to try to make sure that your arrays always have concrete (or at least uniform) element types, but that's not always possible. Given your example x above, you could instead write: x = Array{Int,1}[[0,1],[1,2,3],[0,1,2,4]].
Another alternative is to change your function signature:
foo{N}(x::Array{Array,N}) = 1 # Will *only* work for arrays like x above
foo{T<:Array, N}(x::Array{T,N} = 2 # Will work for all arrays of arrays
The first will only apply if you have exactly that type due to invariance, whereas the second will work for all Arrays of Arrays, both poorly-typed and concrete.
(Edit: As a final note, N<:Number won't match literal numbers. It will match types that are a subtype of Number, like Real or Int. There's currently no way to express that a type parameter must be a value of type Int beyond the convention that N is an integer).

Why do I need a '<' overload for an Array class?

I'm trying to add functionality to an Array class.
So I attempted to add a sort() similar to Ruby's lexicon.
For this purpose I chose the name 'ricSort()' if deference to Swift's sort().
But the compiler says it can't find an overload for '<', albeit the 'sort({$0, $1}' by
itself works okay.
Why?
var myArray:Array = [5,4,3,2,1]
myArray.sort({$0 < $1}) <-- [1, 2, 3, 4, 5]
myArray.ricSort() <-- this doesn't work.
Here's a solution that is close to what you are looking for, followed by a discussion.
var a:Int[] = [5,4,3,2,1]
extension Array {
func ricSort(fn: (lhs: T, rhs: T) -> Bool) -> T[] {
let tempCopy = self.copy()
tempCopy.sort(fn)
return tempCopy
}
}
var b = a.ricSort(<) // [1, 2, 3, 4, 5]
There are two problems with the original code. The first, a fairly simple mistake, is that Array.sort returns no value whatsoever (represented as () which is called void or Unit in some other languages). So your function, which ends with return self.sort({$0 < $1}) doesn't actually return anything, which I believe is contrary to your intention. So that's why it needs to return tempCopy instead of return self.sort(...).
This version, unlike yours, makes a copy of the array to mutate, and returns that instead. You could easily change it to make it mutate itself (the first version of the post did this if you check the edit history). Some people argue that sort's behavior (mutating the array, instead of returning a new one) is undesirable. This behavior has been debated on some of the Apple developer lists. See http://blog.human-friendly.com/swift-arrays-the-bugs-the-bad-and-the-ugly-incomplete
The other problem is that the compiler does not have enough information to generate the code that would implement ricSort, which is why you are getting the type error. It sounds like you are wondering why it is able to work when you use myArray.sort but not when you try to execute the same code inside a function on the Array.
The reason is because you told the compiler why myArray consists of:
var myArray:Array = [5,4,3,2,1]
This is shorthand for
var myArray: Array<Int> = [5,4,3,2,1]
In other words, the compiler inferred that the myArray consists of Int, and it so happens that Int conforms to the Comparable Protocol that supplies the < operator (see: https://developer.apple.com/library/prerelease/ios/documentation/General/Reference/SwiftStandardLibraryReference/Comparable.html#//apple_ref/swift/intf/Comparable)[1]. From the docs, you can see that < has the following signature:
#infix func < (lhs: Self, rhs: Self) -> Bool
Depending on what languages you have a background in, it may surprise you that < is defined in terms of the language, rather than just being a built in operator. But if you think about it, < is just a function that takes two arguments and returns true or false. The #infix means that it can appear between its two functions, so you don't have to write < 1 2.
(The type "Self" here means, "whatever the type is that this protocol implements," see Protocol Associated Type Declaration in https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-XID_597)
Compare this to the signature of Array.sort: isOrderedBefore: (T, T) -> Bool
That is the generic signature. By the time the compiler is working on this line of code, it knows that the real signature is isOrderedBefore: (Int, Int) -> Bool
The compiler's job is now simple, it just has to figure out, is there a function named < that matches the expected signature, namely, one that takes two values of type Int and returns a Bool. Obviously < does match the signature here, so the compiler allows the function to be used here. It has enough information to guarantee that < will work for all values in the array. This is in contrast to a dynamic language, which cannot anticipate this. You have to actually attempt to perform the sort in order to learn if the types can actually be sorted. Some dynamic languages, like JavaScript, will make every possible attempt to continue without failing, so that expressions such as 0 < "1" evaluate correctly, while others, such as Python and Ruby, will throw an exception. Swift does neither: it prevents you from running the program, until you fixed the bug in your code.
So, why doesn't ricSort work? Because there is no type information for it to work with until you have created an instance of a particular type. It cannot infer whether the ricSort will be correct or not.
For example, suppose instead of myArray, I had this:
enum Color {
case Red, Orange, Yellow, Green, Blue, Indigo, Violet
}
var myColors = [Color.Red, Color.Blue, Color.Green]
var sortedColors = myColors.ricSort() // Kaboom!
In that case, myColors.ricSort would fail based on a type error, because < hasn't been defined for the Color enumeration. This can happen in dynamic languages, but is never supposed to happen in languages with sophisticated type systems.
Can I still use myColors.sort? Sure. I just need to define a function that takes two colors and returns then in some order that makes sense for my domain (EM wavelength? Alphabetical order? Favorite color?):
func colorComesBefore(lhs: Color, rhs: Color) -> Bool { ... }
Then, I can pass that in: myColors.sort(colorComesBefore)
This shows, hopefully, that in order to make ricSort work, we need to construct it in such a way that its definition guarantees that when it is compiled, it can be shown to be correct, without having to run it or write unit tests.
Hopefully that explains the solution. Some proposed modifications to the Swift language may make this less painful in the future. In particular creating parameterized extensions should help.
The reason you are getting an error is that the compiler cannot guarantee that the type stored in the Array can be compared with the < operator.
You can see the same sort closure on an array whose type can be compared using < like an Int:
var list = [3,1,2]
list.sort {$0 < $1}
But you will get an error if you try to use a type that cannot be compared with <:
var URL1 = NSURL()
var URL2 = NSURL()
var list = [URL1, URL2]
list.sort {$0 < $1} // error
Especially with all the syntax you can leave out in Swift, I don't see a reason to define a method for this. The following is valid and works as expected:
list.sort(<)
You can do this because < actually defines a function that takes two Ints and returns a Bool just like the sort method is expecting.

How do I compare two arrays in scala?

val a: Array[Int] = Array(1,2,4,5)
val b: Array[Int] = Array(1,2,4,5)
a==b // false
Is there a pattern-matching way to see if two arrays (or sequences) are equivalent?
From Programming Scala:
Array(1,2,4,5).sameElements(Array(1,2,4,5))
You need to change your last line to
a.deep == b.deep
to do a deep comparison of the arrays.
a.corresponds(b){_ == _}
Scaladoc: true if both sequences have
the same length and p(x, y) is true
for all corresponding elements x of
this wrapped array and y of that,
otherwise false
For best performance you should use:
java.util.Arrays.equals(a, b)
This is very fast and does not require extra object allocation. Array[T] in scala is the same as Object[] in java. Same story for primitive values like Int which is java int.
As of Scala 2.13, the deep equality approach doesn't work and errors out:
val a: Array[Int] = Array(1,2,4,5)
val b: Array[Int] = Array(1,2,4,5)
a.deep == b.deep // error: value deep is not a member of Array[Int]
sameElements still works in Scala 2.13:
a sameElements b // true
It didn't look like most of the provided examples work with multidimensional arrays. For example
val expected = Array(Array(3,-1,0,1),Array(2,2,1,-1),Array(1,-1,2,-1),Array(0,-1,3,4))
val other = Array(Array(3,-1,0,1),Array(2,2,1,-1),Array(1,-1,2,-1),Array(0,-1,3,4))
assert(other.sameElements(expected))
returns false, throws an assertion failure
deep doesn't seem to be a function defined on Array.
For convenience I imported scalatest matchers and it worked.
import org.scalatest.matchers.should.Matchers._
other should equal(expected)

Resources