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
Related
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).
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.
I have a Tuple where I have stored anonymous functions, I want to iterate through them and execute them.
val functions = ((x:Int, y:Int) => x + y, (x:Int, y: Int) => x - y)
// I want to execute the anonymous functions in the Tuple
functions.productIterator.foreach(function => function)
Unfortunately I am not able to do
functions.productIterator.foreach(function => function(1, 2))
OR
functions.productIterator.foreach(_(1, 2))
what is the way out.
Tuples are not meant to be iterated over. The types get lost because each entry in a tuple is able to be a different type and so the type system just assumes Any (thus the Iterator[Any]). So the real suggestion is that if you want to iterate, use a collection like a Seq or Set.
On the other hand, if you know that the tuple contains functions of a particular type, then you can bypass the type checking by casting with asInstanceOf, but this is not recommended because type checking is your friend.
functions.productIterator.map(_.asInstanceOf[(Int,Int)=>Int](1, 2))
// produces `Iterator(3, -1)`
Alternatively, have a look at HLists in Shapeless, which have properties of both tuples and collections.
productIterator on a Tuple returns Iterator[Any] and not Iterator[Function2[Int, Int, Int]] as you're expecting.
We can extract the elements of the tuple into a Seq while preserving type information; hence
Seq(functions._1, functions._2).map(_(1,2))
List(3, -1)
If I create a map:
val m = Map((4, 3))
And try to add a new key value pair:
val m_prime = m + (1, 5)
I get:
error: type mismatch;
found : Int(1)
required: (Int, ?)
val m_prime = m + (1, 5)
If I do:
val m_prime = m + ((1, 5))
Or:
val m_prime = m + (1 -> 5)
Then it works. Why doesn't the compiler accept the first example?
I am using 2.10.2
This is indeed very annoying (I run into this frequently). First of all, the + method comes from a general collection trait, taking only one argument—the collection's element type. Map's element type is the pair (A, B). However, Scala interprets the parentheses here as method call parentheses, not a tuple constructor. The explanation is shown in the next section.
To solve this, you can either avoid tuple syntax and use the arrow association key -> value instead, or use double parentheses, or use method updated which is specific to Map. updated does the same as + but takes key and value as separate arguments:
val m_prime = m updated (1, 5)
Still it is unclear why Scala fails here, as in general infix syntax should work and not expect parentheses. It appears that this particular case is broken because of a method overloading: There is a second + method that takes a variable number of tuple arguments.
Demonstration:
trait Foo {
def +(tup: (Int, Int)): Foo
}
def test1(f: Foo) = f + (1, 2) // yes, it works!
trait Baz extends Foo {
def +(tups: (Int, Int)*): Foo // overloaded
}
def test2(b: Baz) = b + (1, 2) // boom. we broke it.
My interpretation is that with the vararg version added, there is now an ambiguity: Is (a, b) a Tuple2 or a list of two arguments a and b (even if a and b are not of type Tuple2, perhaps the compiler would start looking for an implicit conversion). The only way to resolve the ambiguity is to use either of the three approaches described above.
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)