Consider the following function definition:
def foo(l: List[(Char, Int)])
The following expression is valid
l.map(t => t._2 + t._1)
Is there a way to access the elements of the pair by name?
I have tried the following, but it does not compile:
l.map((c: Char, x: Int) => c + x)
There is no way to unpack a tuple with round brackets, you'll need curly ones (which apply a partial function):
l.map { case (c, x) => c + x }
In the future, with Dotty, you should be able to unpack it as follows:
l.map((c, x) => c + x)
Related
Given Scala 2.12.6:
val list = List(1)
val x = 2
This works:
list.map ( y => x + y )
returning List[Int] = List(3)
and this works:
list.map ( (y: Int) => x + y )
returning the same value.
Same for this:
list.map { (y: Int) => x + y }
And same for this:
list.map { y: Int => x + y }
Yet this fails:
list.map ( y: Int => x + y )
producing the error:
error: not found: type +
list.map ( y: Int => x + y )
^
Why is Scala thinking the + is meant to indicate a type, and where is this difference between using parenthesis and curly braces documented and explained?
The Section 6.23 about anonymous functions says:
In the case of a single untyped formal parameter, (x) => e can be abbreviated to x => e. If an anonymous function (x: T) => e with a single typed parameter appears as the result expression of a block, it can be abbreviated to x: T => e.
Thus, in a block { ... }, the function literal (y: Int) => x + y can be abbreviated to just y: Int => x + y.
Without the block, the entire Int => x + y-part is treated as type ascription, so the error message actually makes sense. For example, here is a context in which the offending expression becomes valid:
type y = Unit
type x = Unit
type +[A, B] = Int
val y = (i: Int) => 42 + i
val list = List(1)
println(
list.map ( y: Int => x + y )
) // happily prints `List(43)`.
This is because there are two ys in two separate scopes (one value, one type alias), so that (y: Int => x + y) becomes (y: Int => +[x, y]), and then (y: Int => Int), which is just a type ascription enforcing that value y is indeed of function type Int => Int (which it is, so everything compiles and runs). Here is another similar example.
My suggestion: stick to the slightly more verbose (foo: Foo) => { ... } notation, it will cause fewer surprises for everyone who tries to read and to modify the code. Otherwise there is some risk that
argument types in bindings collide with type ascriptions
=> of the anonymous lambda collides with function type =>
arithmetic operation + collides with binary infix type constructor +[_,_]
values x, y collide with undefined types x, y.
The fact that same syntax can denote both types and expressions can be somewhat of a double-edged sword.
Given a string I want to create a map that for each character in a string will give the number of times the character occurs in a string. The following function makes a map from character to a list of Strings.
def wordOccurrences(w: String) = {
val lower = w.toLowerCase.toList
lower.groupBy(t => t)
}
Now I wanted to alter the last line to:
lower.groupBy(t => t) map ( (x,y) => x -> y.length)
But it doesn't work, can someone explain why and how to fix it?
For mapping purposes, a Map[K, V] is an Iterable[(K, V)] (notice the extra pair of parentheses, identifying a tuple type), meaning that when you map over it you have pass a function that goes from (K, V) to your target type.
What you are doing, however, is passing a function that takes two independent arguments, rather then a single tuple argument.
The difference can be seen by inspecting the types of these two functions in the Scala shell:
scala> :t (a: Int, b: Int) => a + b
(Int, Int) => Int
scala> :t (p: (Int, Int)) => p._1 + p._2
((Int, Int)) => Int
Notice how the former takes two arguments while the latter takes a single tuple.
What you can do is pass a function which decomposes the tuple so that you can bind the components of the tuple independently:
lower.groupBy(t => t) map { case (x, y) => x -> y.length }
or alternatively pass a function which uses the tuple without deconstructing it
lower.groupBy(t => t) map (p => p._1 -> p._2.length)
Note
Dotty, which is the current project Scala's original author Martin Odersky is working on and that will probably become Scala 3, supports the syntax you are proposing, calling the feature function arity adaptation. This has been discussed, along with other feature, in Odersky's 2016 Keynote at Scala eXchange, "From DOT to Dotty" (here the video taped at 2017 Voxxed Days CERN).
You can use
lower.groupBy(t => t).mapValues(_.length)
I've a question regarding this pattern matching in scala:
val div: (Double, Double) => Double = {
case (x, y) if y != 0 => x / y
}
I've understand how pattern matching works and its syntaxis in scala, but this expression drives me crazy. How does complier knows that x and y is an arguments of the function and pattern match on them?
The rules for this are defined in section 8.5 "Pattern Matching Anonymous Functions" of the Scala Language Specification. If using an anonymous function with pattern matching, the type must be partially provided. You do that by saying the type is (Double, Double) => Double, which is shorthand for Function2[Double, Double, Double].
Now:
If the expected type is scala.Function k [S1,…,Sk, R], the expression is taken to be equivalent to the anonymous function:
(x1:S1,…,xk:Sk) => (x1,…,xk) match {
case p1 => b1 … case pn => bn
}
So no matter what the arity of your function, the pattern match is passed a tuple of the function's arguments, hence you can use the regular tuple extractor syntax.
So your example is short for
val div: (Double, Double) => Double = (a, b) => (a, b) match {
case (x, y) if y != 0 => x / y
}
or
val div = (a: Double, b: Double) => (a, b) match {
case (x, y) if y != 0 => x / y
}
The naming of the extractor parameters x and y is up to your imagination. You decide how to call the resulting elements of the extractor, you could as well write case (foo, bar) => ...
As far as I know, the infix operator usage in Scala should be equivalent to the invocation of a method. So:
scala> "a" + 3.toString
res0: java.lang.String = a3
Is the same as:
scala> "a".+(3.toString)
res1: java.lang.String = a3
I came across an occasion where this is not happening, when there is a placeholder. I was doing something more complex, but it can be distilled to:
scala> def x(f:(Int)=>String) = f(3)
x: (f: Int => String)String
scala> x("a" + _.toString)
res3: String = a3
So far so good. But...
scala> x("a".+(_.toString))
<console>:9: error: missing parameter type for expanded function ((x$1) => x$1.toString)
x("a".+(_.toString))
What's the difference here? What am I missing?
Jordi
The _ placeholder can only appear at the topmost Expr in its function. That means
(_.toString)
is itself a function, and "a" + some function of unknown type doesn't make much sense to the compiler.
Your assessment of infix notation is correct, but your understanding of placeholder parameters is flawed.
When you use underscore as a placeholder parameter, you are creating a function. The question is what are the boundaries of that function: where does it start, where does it end? For example, consider this expression:
_ + _ + _
How should it be translated? Here are some alternatives:
(x, y, z) => { x + y + z }
(x, y) => { (z) => { x + y } + z }
(x) => { x + { (y, z) => y + z } }
Well, Scala rule is that the scope is the innermost parenthesis-delimited expression, or the whole expression otherwise. So, in practice, you wrote two different things:
x("a" + _.toString) // is the same thing as
x((y) => "a" + y.toString)
x("a".+(_.toString)) // is the same thing as
x("a".+((y) => y.toString))
I had a List of Scala tuples like the following:
val l = List((1,2),(2,3),(3,4))
and I wanted to map it in a list of Int where each item is the sum of the Ints in a the corresponding tuple. I also didn't want to use to use the x._1 notation so I solved the problem with a pattern matching like this
def addTuple(t: (Int, Int)) : Int = t match {
case (first, second) => first + second
}
var r = l map addTuple
Doing that I obtained the list r: List[Int] = List(3, 5, 7) as expected. At this point, almost by accident, I discovered that I can achieve the same result with an abbreviated form like the following:
val r = l map {case(first, second) => first + second}
I cannot find any reference to this syntax in the documentation I have. Is that normal? Am I missing something trivial?
See Section 8.5 of the language reference, "Pattern Matching Anonymous Functions".
An anonymous function can be defined by a sequence of cases
{case p1 =>b1 ... case pn => bn }
which appear as an expression without a prior match. The expected type of such an expression must in part be defined. It must be either scala.Functionk[S1, ..., Sk, R] for some k > 0, or scala.PartialFunction[S1, R], where the argument type(s) S1, ..., Sk must be fully determined, but the result type R may be undetermined.
The expected type deternines whether this is translated to a FunctionN or PartialFunction.
scala> {case x => x}
<console>:6: error: missing parameter type for expanded function ((x0$1) => x0$1 match {
case (x # _) => x
})
{case x => x}
^
scala> {case x => x}: (Int => Int)
res1: (Int) => Int = <function1>
scala> {case x => x}: PartialFunction[Int, Int]
res2: PartialFunction[Int,Int] = <function1>
{case(first, second) => first + second} is treated as a PartialFunction literal. See examples in "Partial Functions" section here: http://programming-scala.labs.oreilly.com/ch08.html or section 15.7 of Programming in Scala.
Method map accepts a function. In your first example you create a function, assign it to a variable, and pass it to the map method. In the second example you pass your created function directly, omitting assigning it to a variable. You are doing just the same thing.