Scala operator associativity (2nd parameter lists) - scala

Is it possible to call an apply function directly on the result of a method which takes a second parameter list (with an implicit arg)? Even with parentheses in the logical place, I get the same compile-time type error, which indicates it doesn't parse it as expected.
val x = Map(1 -> 2, 2->4, 3-> 6) //1
val y = x.map(_.swap) //2
y(4) //3
x.map(_.swap)(4) //4
((x.map(_.swap))(4) //5
Line 4 makes sense to not parse since the (4) easily appears to be the second parameter list for map(), but line 5, there is a set of ()'s around the .map expression, yet it still associates the (4) to the .map rather than the result of .map().
Is there a way to do lines 2 and 3 in one expression?
EDIT: I'm aware of .apply(), which is what the compiler will insert itself. Is there a way to do this without manually de-sugaring?

Yes there are several possible solutions.
All work by either satisfying the implicit parameter list or giving the compiler a hint that expression has ended and the (), read apply, is really the apply-method and no second argument list.
1. Calling .apply()
scala> Map(1 -> 2, 2 -> 4, 3 -> 6).map(_.swap).apply(4)
res7: Int = 2
2. Supplying the implicit directly
Another option is supplying the implicit directly
Example with breakout
import scala.collection.breakOut
scala> List(1).map(_ + 1)(breakOut)(0)
res38: Int = 2
I think the general problem is: You have to fill to provide the implicit for the CanBuildFrom to work properly or explicitly state that you want to call apply and not fill the second parameter list.
You can find more in http://docs.scala-lang.org/tutorials/FAQ/breakout. Opposing to the name the secCanBuildFrom works.

Related

Map data type creation

What does this expression do?
val m = Map(1 -> 2, 2 -> 4)
This is the return value:
scala.collection.immutable.Map[Int, Int] = Map(1 -> 2, 2 -> 4)
What does this expression do?
Note: this is not an expression, it is a value definition. A val definition does not have a value.
The part after the = sign is an expression, though.
val m = Map(1 -> 2, 2 -> 4)
In Scala, foo(bar) can mean one of two things:
calling the method foo implicitly on this passing bar as an argument.
calling the method apply on the object obtained by evaluating the expression foo passing bar as an argument.
So, foo(bar) is equivalent to either
this.foo(bar)
or
foo.apply(bar)
depending on which is available in the current scope.
In this particular case, there is no method named Map defined in the current scope, it corresponds to the second meaning:
Map.apply(1 -> 2, 2 -> 4)
Where does Map come from? This is actually scala.Predef.Map, which is defined in scala.Predef which is an object that gets automatically imported into every Scala program. Note: don't confuse the value scala.Predef.Map which is an alias for the object scala.collection.immutable.Map with the type alias scala.Predef.Map[A, B] which is an alias for the trait scala.collection.immutable.Map.
Values and types live in completely separate universes in Scala (like in most other programming languages), therefore it is perfectly possible for them to have the same name, since they can never appear in the same context and thus there can never be an ambiguity.
So, let's look at the documentation for Map.apply to tell us what it does:
def apply[A, B](elems: (A, B)*): Map[A, B]
A collection of type Map that contains given key/value bindings.
So, Map.apply returns a Map that contains the key/value pairs that we pass as arguments. But wait, apply takes repeated parameters of type (A, B) (which is syntactic sugar for Tuple2[A, B]), but we are not passing a Tuple2, i.e. we are not passing (1, 2), (2, 4) as arguments but rather 1 -> 2, 2 -> 4, so what is this?
Remember that in Scala, a much wider range of identifiers is allowed than in many other languages. Also remember that methods can be called without a period, and that if a method is called without a period and you are passing only a single argument, you can leave out the parentheses. So,
1 -> 2
is the same as
1 ->(2)
is the same as
1.->(2)
All this does is call the method -> (which is just a boring standard Scala method name, nothing at all special about it) on 1 passing 2 as the argument. Now, it turns out that Int doesn't have a -> method, but there is an implicit class ArrayAssoc which adds the methods -> as well as → to Any type and … tadaaa … returns a Tuple2[A, B].
Alright. Putting it all together:
1 -> 2
is the same as
1 ->(2)
is the same as
1.->(2)
which is actually calling ArrowAssoc.-> which returns
(1, 2)
which is syntactic sugar for
new Tuple2(1, 2)
(and the same for 2 -> 4) which we are passing to
Map(new Tuple2(1, 2), new Tuple2(3, 4))
which is actually
scala.Predef.Map(new Tuple2(1, 2), new Tuple2(3, 4))
which is assigned to
scala.collection.immutable.Map(new Tuple2(1, 2), new Tuple2(3, 4))
which is actually
scala.collection.immutable.Map.apply(new Tuple2(1, 2), new Tuple2(3, 4))
which returns a new instance of some unspecified implementation class of the trait scala.collection.immutable.Map[Int, Int] with the key 1 associated with the value 2 and the key 2 associated with the value 4.
This is the return value:
scala.collection.immutable.Map[Int, Int] = Map(1 -> 2, 2 -> 4)
To be pedantic: this is the string representation of the return value, obtained by calling toString() on it. Map overrides toString() and represents its contents using the same -> that could be used to construct it.
a -> b is syntactic sugar for creating a tuple (a, b).
The scala Map constructor takes an arbitrary number of tuples (a, b) as arguments and creates a mapping from the first element of each tuple to the second. In your case, since you are populating it with integers, it generates a Map[Int, Int]: A mapping from integers to integers.
You can now use your map e.g. as follows:
m(1) // Has value 2
m(2) // Has value 4

What's the meaning of -> in scala

When I read the book 《Functional Programming in scala》.
I find the expression like this:
case (Cons(h, t), Empty) =>
Some(f(Some(h()), Option.empty[B]) -> (t(), empty[B]))
What's the difference between
Some(f(Some(h()), Option.empty[B]), (t(), empty[B]))
If your 2nd example compiles, it should compile with a warning: creating a 2-tuple: this may not be what you want Otherwise it would fail because Some() doesn't take two parameters. The 1st example should compile because the -> is explicitly creating the tuple to send as a single parameter to the (outer) Some().
When creating a tuple of two elements you have the option of using parentheses and comma (5, true), or the arrow 5 -> true. In most situations the parentheses are optional when using the arrow version.
The arrow can't be used if you want more than 2 elements (i.e. not nested tuples):
'c' -> 'b' -> 'x'
//res0: ((Char, Char), Char) = ((c,b),x)
The -> is actually a method of the ArrowAssoc class to which every object can be implicitly converted. See the object scala.Predef. It is defined as:
def -> [B](y: B): Tuple2[A, B] = Tuple2(x, y)
This means that 1 -> 2 is equivalent to 1.->(2) which evaluates to Tuple2(1, 2). This is also explained in section 21.4 of the book (3rd edition).

How can I find the definition of methods/operations defined in an implicitly-converted class?

I'm looking at someone else's source code (Scala), where I see the operator :+= being called on a variable of type IndexedSeq. I am looking all over the scaladocs page for that class to figure out what that operator does, but I do not see it. I'm thinking that either it's defined in a class outside of IndexedSeq's inheritance hierarchy, or else the javascript on the scaladocs page is hiding it somewhere I can't see it. (Actually it's neither; see answer below.)
I've hit every button on the scaladocs page trying to unhide everything. I've looked in the web-page's HTML code. There has got to be a way to look up an operator from the documentation of a class to which it can be applied. Hasn't there?
(N.B.: I looked up that operator using symbolhound, so I know what that operator means now. This question is about scala documentation in general, not that particular operator.)
All operators in Scala are normal methods.
You cannot find it because it is compiler magic for re-assignement, it is not an operator. Or to say it another way: it looks like an operator of its own, but it is actually "an operator followed by the = character".
The compiler will magically turn that into a assignment if the operator (here :+) returns the proper type, and the original value was a var, obviously.
Since it is not provided by any implicit nor explicit method on Seq[T] or whatever, it does not appear anywhere in the generated scaladoc.
So to answer the general question:
It is a language construct, so the only place where it is documented is the specification, sadly,
but, if you find some "<?>=" unknown operator somewhere, look for the definition of "<?>", that one is sure to be documented.
Edit: I finally found where this is defined in the SLS:
§6.12.4:
An assignment operator is an operator symbol (syntax category op in (§1.1)) that
ends in an equals character “=”, with the exception of operators for which one of the
following conditions holds:
(1) the operator also starts with an equals character, or
(2) the operator is one of (<=), (>=), (!=).
It also says later on that it only happens when all other options have been tried (including potential implicits).
Is this value assigned to a variable? If it's the case I think this syntax sugar:
scala> var x = IndexedSeq(1,2,3)
x: IndexedSeq[Int] = Vector(1, 2, 3)
scala> x :+= 10
scala> x
res59: IndexedSeq[Int] = Vector(1, 2, 3, 10)
scala> val y = IndexedSeq(1,2,3)
y: IndexedSeq[Int] = Vector(1, 2, 3)
scala> y :+= 10
<console>:16: error: value :+= is not a member of IndexedSeq[Int]
y :+= 10
^
It is syntax sugar for "operation and assignment", like +=:
scala> var x = 10
x: Int = 10
scala> x += 1
scala> x
res63: Int = 11
Which de-sugars to x = x + 1.

Adding an (Int, Int) tuple to a Set in scala [duplicate]

Are the parenthesis around the final tuple really needed? It doesn't compile without them and the compiler tries to add only the Sort("time") and complains that it expects a tuple instead.
val maxSortCounts: Map[Sort, Int] =
sorts.map(s => s -> usedPredicates.map(pred => pred.signature.count(_ == s)).max)
.toMap + ((Sort("time"), 1))
I've tried to reproduce this behaviour inside the REPL with a shorter example, but there it behaves as intended. The variable sorts is a Seq[Sort].
error: type mismatch;
found : <snip>.Sort
required: (<snip>.Sort, Int)
.toMap + (Sort("time"), 1)
Yes, they are needed. Otherwise the compiler will interpret the code as
x.+(y, z) instead of x.+((y, z)).
Instead, you can use ArrowAssoc again: x + (y -> z). Notice, the parentheses are also needed because + and - have the same precedence (only the first sign of a method defines its precedence).
Yes, they're needed. They make the expression a tuple. Parentheses surrounding a comma-separated list create tuple objects. For example, (1, 2, 3) is a 3-tuple of numbers.
Map's + method accepts a pair - in other words a tuple of two elements. Map represents entries in the map as (key,value) tuples.

Get item in the list in Scala?

How in the world do you get just an element at index i from the List in scala?
I tried get(i), and [i] - nothing works. Googling only returns how to "find" an element in the list. But I already know the index of the element!
Here is the code that does not compile:
def buildTree(data: List[Data2D]):Node ={
if(data.length == 1){
var point:Data2D = data[0] //Nope - does not work
}
return null
}
Looking at the List api does not help, as my eyes just cross.
Use parentheses:
data(2)
But you don't really want to do that with lists very often, since linked lists take time to traverse. If you want to index into a collection, use Vector (immutable) or ArrayBuffer (mutable) or possibly Array (which is just a Java array, except again you index into it with (i) instead of [i]).
Safer is to use lift so you can extract the value if it exists and fail gracefully if it does not.
data.lift(2)
This will return None if the list isn't long enough to provide that element, and Some(value) if it is.
scala> val l = List("a", "b", "c")
scala> l.lift(1)
Some("b")
scala> l.lift(5)
None
Whenever you're performing an operation that may fail in this way it's great to use an Option and get the type system to help make sure you are handling the case where the element doesn't exist.
Explanation:
This works because List's apply (which sugars to just parentheses, e.g. l(index)) is like a partial function that is defined wherever the list has an element. The List.lift method turns the partial apply function (a function that is only defined for some inputs) into a normal function (defined for any input) by basically wrapping the result in an Option.
Why parentheses?
Here is the quote from the book programming in scala.
Another important idea illustrated by this example will give you insight into why arrays are accessed with parentheses in Scala. Scala has fewer special cases than Java. Arrays are simply instances of classes like any other class in Scala. When you apply parentheses surrounding one or more values to a variable, Scala will transform the code into an invocation of a method named apply on that variable. So greetStrings(i) gets transformed into greetStrings.apply(i). Thus accessing an element of an array in Scala is simply a method call like any other. This principle is not restricted to arrays: any application of an object to some arguments in parentheses will be transformed to an apply method call. Of course this will compile only if that type of object actually defines an apply method. So it's not a special case; it's a general rule.
Here are a few examples how to pull certain element (first elem in this case) using functional programming style.
// Create a multdimension Array
scala> val a = Array.ofDim[String](2, 3)
a: Array[Array[String]] = Array(Array(null, null, null), Array(null, null, null))
scala> a(0) = Array("1","2","3")
scala> a(1) = Array("4", "5", "6")
scala> a
Array[Array[String]] = Array(Array(1, 2, 3), Array(4, 5, 6))
// 1. paratheses
scala> a.map(_(0))
Array[String] = Array(1, 4)
// 2. apply
scala> a.map(_.apply(0))
Array[String] = Array(1, 4)
// 3. function literal
scala> a.map(a => a(0))
Array[String] = Array(1, 4)
// 4. lift
scala> a.map(_.lift(0))
Array[Option[String]] = Array(Some(1), Some(4))
// 5. head or last
scala> a.map(_.head)
Array[String] = Array(1, 4)
Please use parentheses () to access the list of elements, as shown below.
list_name(index)