Usage of _ in scala lambda functions - scala

Can anyone please explain me why I can do:
a.mapValues(_.size)
instead of
a.mapValues(x => x.size)
but I can't do
a.groupBy(_)
instead of a
a.groupBy(x => x)

When you write a.groupBy(_) the compiler understands it as an anonymous function:
x => a.groupBy(x)
According to Scala Specifications §6.23, an underscore placeholder in an expression is replaced by a anonymous parameter. So:
_ + 1 is expanded to x => x + 1
f(_) is expanded to x => f(x)
_ is not expanded by itself (the placeholder is not part of any expression).
The expression x => a.groupBy(x) will confuse the compiler because it cannot infer the type of x. If a is some collection of type E elements, then the compiler expects x to be a function of type (E) => K, but type K cannot be inferred...

It isn't easy to see it here:
a.groupBy(_)
But it's easier to see it in something like this:
a.mkString("<", _, ">")
I'm partially applying the method/function. I'm applying it to some parameters (the first and last), and leaving the second parameter unapplied, so I'm getting a new function like this:
x => a.mkString("<", x, ">")
The first example is just a special case where the sole parameter is partially applied. When you use underscore on an expression, however, it stands for positional parameters in an anonymous function.
a.mapValues(_.size)
a.mapValues(x => x.size)
It is easy to get confused, because they both result in an anonymous function. In fact, there's a third underscore that is used to convert a method into a method value (which is also an anonymous function), such as:
a.groupBy _

Related

Folding lists in scala

Folding list in scala using /: and :\ operator
I tried to to look at different sites and they only talk about foldRight and foldLeft functions.
def sum(xs: List[Int]): Int = (0 /: xs) (_ + _)
sum(List(1,2,3))
res0: 6
The code segment works as described. But I am not able to completely understand the method definition. What I understand is that the one inside the first parenthesis -> 0 /: xs where /: is a right associate operator. The object is xs and the parameter is 0. I am not sure about the return type of the operation (most probably it would be another list?). The second part is a functional piece which sums its two parameters. But I don't understand what object invokes it ? and the name of function. Can someone please help me to understand.
The signature of :/ is
/:[B](z: B)(op: (B, A) ⇒ B): B
It is a method with multiple argument lists, so when it is just invoked with on argument (i.e. 0 /: xs in your case) the return type is (op: (B, A) ⇒ B): B. So you have to pass it a method with 2 parameters ( _ + _ ) that is used to combine the elements of the list starting from z.
This method is usually called foldLeft:
(0 /: xs)(_ + _) is the same as xs.foldLeft(0)(_ + _)
You can find more details here: https://www.scala-lang.org/api/2.12.3/scala/collection/immutable/List.html
Thanks #HaraldGliebe & #LuisMiguelMejíaSuárez for your great responses. I am enlightened now!. I am just summarisig the answer here which may benefit others who read this thread.
"/:" is actually the name of the function which is defined inside the List class. The signature of the function is: /:[B](z: B)(op: (B, A) ⇒ B): B --> where B is the type parameter, z is the first parameter; op is the second parameter which is of functional type.
The function follows curried version --> which means we can pass less number of parameters than that of the actual number. If we do that,
the partially applied function is stored in a temporary variable; we can then use the temporary variable to pass the remaining parameters.
If supplied with all parameters, "/:" can be called as: x./:(0)(_+_) where x is val/var of List type. OR "/:" can be called in two steps which are given as:
step:1 val temp = x./:(0)(_) where we pass only the first parameter. This results in a partially applied function which is stored in the temp variable.
step:2 temp(_+_) here using the partially applied function temp is passed with the second (final) parameter.
If we decide to follow the first style ( x./:(0)(_+_) ), calling the first parameter can be written in operator notion which is: x /: 0
Since the method name ends with a colon, the object will be pulled from right side. So x /: 0 is invalid and it has to be written as 0 /: x which is correct.
This one is equivalent to the temp variable. On following 0 /: x, second parameter also needs to be passed. So the whole construct becomes: (0/:x)(_+_)
This is how the definition of the function sum in the question, is interpreted.
We have to note that when we use curried version of the function in operator notion, we have to supply all the parameters in a single go.
That is: (0 /: x) (_) OR (0 /: x) _ seems throwing syntax errors.

Behaviour of Scala underscore not work like element of list

Hi I am new in scala, and of course have a newbie question,
why the underscore character not work in this cases
my undertanding about underscore in this case it represent one element of the list
val listOftuple = List(("cat","tom"),("mouse","jerry"),("dog","spike"))
val listOfarray = List(Array("cat","tom"),Array("mouse","jerry"),Array("dog","spike"))
tuplelist.map(it=>it._1+it._2) //Ok
tuplelist.map(_._1+_._2) //Not work, give me: error: missing parameter type for expanded function
listOfarray.map(_.length) //Here work, like array.length
listOfarray.map(it=>it(0)+it(1)) //Ok
listOfarray.map(_=>_(0)+_(1))//Not work, give me: error: missing parameter type for expanded function
listOfarray.map(_(0)+_(1))//Not work, give me: error: missing parameter type for expanded function
may be i fall in a lexical misunderstanding ?
how to fix the error msg?
greetings
tuplelist.map(_._1+_._2)
Each time you use _, it stands for another parameter. That is, _ + _ is equivalent to (x,y) => x+y, not x => x+x. So the above is equivalent to tuplelist.map((x, y) => _._1 + _._2), which does not work because map expects a function that takes only one argument.
listOfarray.map(_=>_(0)+_(1))
Using _ as the name of a function parameter just means that the parameter will be ignored. When you use _ inside the function's body, it is still the function shortcut operator, not a reference to the ignored parameter. So the above lambda is equivalent to ignoredParam => (x, y) => x + y.
listOfarray.map(_(0)+_(1))
(x,y) => x(0) + y(1), but you want x => x(0) + x(1).
how to fix the error msg?
In all of these cases, using an explicit parameter list is the correct solution. You simply can't use the shortcut notation if you want to use the same parameter more than once.

Scala collections: why do we need a case statement to extract values tuples in higher order functions?

Related to Tuple Unpacking in Map Operations, I don't understand why do we need a case (that looks like a partial function to me) to extract values from tuple, like that:
arrayOfTuples map {case (e1, e2) => e1.toString + e2}
Instead of extracting in the same way it works in foldLeft, for example
def sum(list: List[Int]): Int = list.foldLeft(0)((r,c) => r+c)
Anyway we don't specify the type of parameters in the first case, so why do we need the case statement?
Because in Scala function argument lists and tuples are not a unified concept as they are in Haskell and other functional languages. So a function:
(t: (Int, Int)) => ...
is not the same thing as a function:
(e1: Int, e2: Int) => ...
In the first case you can use pattern matching to extract the tuple elements, and that's always done using case syntax. Actually, the expression:
{case (e1, e2) => ...}
is shorthand for:
t => t match {case (e1, e2) => ...}
There has been some discussions about unifying tuples and function argument lists, but there are complications regarding Java overloading rules, and also default/named arguments. So, I think it's unlikely the concepts will ever be unified in Scala.
Lambda with one primitive parameter
With
var listOfInt=(1 to 100).toList
listOfInt.foldRight(0)((current,acc)=>current+acc)
you have a lambda function operating on two parameter.
Lambda with one parameter of type tuple
With
var listOfTuple=List((1,"a"),(2,"b"),(3," "))
listOfTuple.map(x => x._1.toString + x._2.toString)
you have a lambda function working on one parameter (of type Tuple2[Int, String])
Both works fine with type inference.
Partial lambda with one parameter
With
listOfTuple.map{case (x,y) => x.toString + y.toString}
you have a lambda function, working with one parameter (of type Tuple2[Int, String]). This lambda function then uses Tuple2.unapply internally to decompose the one parameter in multiple values. This still works fine with type inference. The case is needed for the decomposition ("pattern matching") of the value.
This example is a little bit unintuitive, because unapply returns a Tuple as its result. In this special case there might indeed be a trick, so Scala uses the provided tuple directly. But I am not really aware of such a trick.
Update: Lambda function with currying
Indeed there is a trick. With
import Function.tupled
listOfTuple map tupled{(x,y) => x.toString + y.toString}
you can directly work with the tuple. But of course this is really a trick: You provide a function operating on two parameters and not with a tuple. tupled then takes that function and changes it to a different function, operating on a tuple. This technique is also called uncurrying.
Remark:
The y.toString is superfluous when y is already a string. This is not considered good style. I leave it in for the sake of the example. You should omit it in real code.

Named parameters vs _, dot notation vs infix operation, curly vs round brackets when using higher-order functions in Scala

I'm having the hardest time understanding when I can or can't omit brackets and/or periods, and how this interplays with _.
The specific case I had with this was
val x: X = ???
val xss: List[List[X]] = ???
xss map x :: _ //this doesn't compile
xss map _.::(x) //this is the same as the above (and thus doesn't compile)
the above two seem to be identical to xss.map(_).::(x)
xss map (x :: _) //this works as expected
xss map {x :: _} //this does the same thing as the above
meanwhile, the following also fail:
xss.map xs => x :: xs //';' expected but '=>' found.
xss.map x :: _ //missing arguments for method map in class List; follow this method with `_' if you want to treat it as a partially applied function
//so when I try following the method with _, I get my favourite:
xss.map _ x :: _ //Cannot construct a collection of type That with elements of type B based on a collection of type List[List[Main.X]]
//as opposed to
xss map _ x :: _ //missing parameter type for expanded function ((x$1) => xss.map(x$1).x(($colon$colon: (() => <empty>))))
Right now, I often play "toggle the symbols until it compiles" which I believe to be a suboptimal programming strategy. How does this all work?
First we need to distinguish between xss.map(f) and xss map f. According to Scala Documentation any method which takes a single parameter can be used as an infix operator.
Actually map method in List is one of these methods. Ignoring the full signature and the fact that it's inherited from TraversableLike, the signature is as follows:
final def map[B](f: (A) ⇒ B): List[B]
So it takes a single parameter, namely f, which is a function with type A => B. So if you have a function value defined as
val mySize = (xs:List[Int]) => xs.size
you can choose between
xss.map(mySize)
or
xss map mySize
This is a matter of preference but according to Scala Style Guide, for this case, the latter is preferred, unless if it is part of a complex expression where it's better to stick with dot notation.
Note that if you opt to use the dot notation you always need to qualify the function application with brackets! That's why none of the following compiles successfully.
xss.map xs => x :: xs // Won't compile
xss.map x :: _ // Won't compile
xss.map _ x :: _ // Won't compile
But most of the time instead of passing a function value you need to pass a function literal (aka anonymous function). In this case again if you use the dot notation you need something like xss.map(_.size). But if you use the infix notation, it will be a matter of precedence.
For example
xss map x :: _ // Won't compile!
does not work because of operator precedence. So you need to use brackets to disambiguiate the situation for compiler by xss map (x :: _).
Use of curly braces instead of brackets has a very clear and simple rule. Again any function which takes only one parameter can be applied with curly braces instead of brackets, both for infix and dot notations. So the following statements will compile.
xss.map{x :: _}
xss map {x :: _}
For avoiding confusions you can begin with dot notation and explicit types for parameters. Later after being compiled - and probably writing some unit tests for your code - you can start refactoring the code by removing unnecessary types, using infix notation, and using curly braces instead of brackets where it makes sense.
For this purpose you can refer to Scala Style Guide and Martin Odersky's talk in Scala Days 2013 which is concerning Scala coding style. Also you can always ask for help from IDEs for refactoring the code to be more concise.

Scala underscore minimal function

Let's create a value for the sake of this question:
val a = 1 :: Nil
now, I can demonstrate that the anonymous functions can be written in shorthand form like this:
a.map(_*2)
is it possible to write a shorthand of this function?:
a.map((x) => x)
my solution doesn't work:
a.map(_)
For the record, a.map(_) does not work because it stands for x => a.map(x), and not a.map(x => x). This happens because a single _ in place of a parameter stands for a partially applied function. In the case of 2*_, that stands for an anonymous function. These two uses are so close that is very common to get confused by them.
Your first shorthand form can also be written point-free
a map (2*)
Thanks to multiplication being commutative.
As for (x) => x, you want the identity function. This is defined in Predef and is generic, so you can be sure that it's type-safe.
You should use identity function for this use case.
a.map(identity)
identity is defined in scala.Predef as:
implicit def identity[A](x: A): A = x