why scala lambda with _ can't using && to combine two bool expression - scala

As far as I understand .
_ is a short lambda to omit a=>
i find this code (can find here scala-function-true-power)
val file = List("warn 2013 msg", "warn 2012 msg", "error 2013 msg", "warn 2013 msg")
val size = file.filter(_.contains("warn")).filter(_.contains("2013")).size
//val size1 = file.filter(_.contains("warn") && _.contains("2013")).size
val size2 = file.filter( a=> a.contains("warn") && a.contains("2013")).size
println("cat file | grep 'warn' | grep '2013' | wc : " +size )
the line to get size1 has syntax error,looks like it can't recognize the "_" ,it's not a element in fileList.
but i use a=>,the normal kind,it works good .
so,why the scala work by this way?
is there more difference in _ and a=> ?

In scala, any _ placeholder is matched against the passed arguments in the context of calling function. So for example if the signature of the function you are trying to use is f : A ⇒ B and you are calling something like collectionOfFunctA.map(_.f) - Scala compiler will infer the correct type of the function and will use the first underscore to put the actual item from a collection and call the function f over it. But if you will try to write it as collectionOfFunctA.map(_.f + _.size) - that will fail, because Scala compiler will pick up the first placeholder as of type that has function f defined, and the second underscore will not match any function in the context. So it will expect to have a function that takes two parameters instead of one.
More on this

As jdevelop says, but here in the words of the compiler/REPL:
scala> val size1 = file.filter(_.contains("warn") && _.contains("2013")).size
<console>:8: error: missing parameter type for expanded function ((x$1, x$2) => x$1.contains("warn").$amp$amp(x$2.contains("2013")))
val size1 = file.filter(_.contains("warn") && _.contains("2013")).size
^
<console>:8: error: missing parameter type for expanded function ((x$1: <error>, x$2) => x$1.contains("warn").$amp$amp(x$2.contains("2013")))
val size1 = file.filter(_.contains("warn") && _.contains("2013")).size
^
You see that hint: for expanded function ((x$1, x$2) => x$1.contains("warn").$amp$amp(x$2.contains("2013")))
It is expecting 2 parameters while there is just one.

You can think of the place holder as being matched with the lambda's arguments positionnally.
The first occurrence of the _ is matched with the first argument, the second occurence is matched with the second argument, etc.
As the other answers have shown, this means that using the placeholder twice will be desugared as trying to pass a lamba with 2 arguments to the filter which only expects one.
In your example :
val size = file.filter(_.contains("warn") && _.contains("2013")).size
would be desugared as
val size = file.filter((a,b)=>a.contains("warn") && b.contains("2013")).size
which will not compile since filter expects a predicate p: A => Boolean
Now, a reason the placeholder is matched positionnally is to avoid ambiguity in lambdas with more than one argument.
How can the compiler guess the correct implementation for the following case if the place holder can be reused multiple times for the same argument:
file.fold("")(_++_)
Should it be desugared as :
file.fold("")((a,b)=> a++b )
or as
file.fold("")((a,b)=> a++a )
or as
file.fold("")((a,b)=> b++b )
and worse, what would you expect for
file.fold("")(_++_++_)
There is no general way for the compiler to infer the correct implementation.
One might argue for relaxing the constraint when the expected lambda only accepts one argument. I suggest doing a more detailed research before taking the first steps to the scala improvement process as it seems likely that this particular design decision has been challenged and explained before.
If you are worried about the performance of iterating over the list twice (which is the case when you write)
file.filter(_.contains("warn")).filter(_.contains("2013")).size
In theory it should be possible for the compiler to detect that both filters can be applied within the same iteration.
In scala, the collections are eager by default but you can get the lazy evaluation by using views.
The current implementation has known issues which are being worked on. Other collection implementations in scala are actively being developed to be able to combine transformations and computations by default (see psp-std for example)

Related

What does an underscore after a scala method call mean?

The scala documentation has a code example that includes the following line:
val numberFunc = numbers.foldLeft(List[Int]())_
What does the underscore after the method call mean?
It's a partially applied function. You only provide the first parameter to foldLeft (the initial value), but you don't provide the second one; you postpone it for later. In the docs you linked they do it in the next line, where they define squares:
val numberFunc = numbers.foldLeft(List[Int]())_
val squares = numberFunc((xs, x) => xs:+ x*x)
See that (xs, x) => xs:+ x*x, that's the missing second parameter which you omitted while defining numberFunc. If you had provided it right away, then numberFunc would not be a function - it would be the computed value.
So basically the whole thing can also be written as a one-liner in the curried form:
val squares = numbers.foldLeft(List[Int]())((xs, x) => xs:+ x*x)
However, if you want to be able to reuse foldLeft over and over again, having the same collection and initial value, but providing a different function every time, then it's very convinient to define a separate numbersFunc (as they did in the docs) and reuse it with different functions, e.g.:
val squares = numberFunc((xs, x) => xs:+ x*x)
val cubes = numberFunc((xs, x) => xs:+ x*x*x)
...
Note that the compiler error message is pretty straightforward in case you forget the underscore:
Error: missing argument list for method foldLeft in trait
LinearSeqOptimized Unapplied methods are only converted to functions
when a function type is expected. You can make this conversion
explicit by writing foldLeft _ or foldLeft(_)(_) instead of
foldLeft. val numberFunc = numbers.foldLeft(ListInt)
EDIT: Haha I just realized that they did the exact same thing with cubes in the documentation.
I don't know if it helps but I prefer this syntax
val numberFunc = numbers.foldLeft(List[Int]())(_)
then numberFunc is basically a delegate corresponding to an instance method (instance being numbers) waiting for a parameter. Which later comes to be a lambda expression in the scala documentation example

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.

Get a different result when calling the same function

I am a scala newbie.
This is my code. The results of two types of same method use are different,
can anyone explain to me why???
The thing is that in Scala, all functions ( or "operators") which have names ending with a colon ':' are deemed as right associative when used with infix notation.
So... for your function,
def ::(t: TG) = ???
When, you are writing
val lxx3 = lxx1 :: lxx2
The function :: associates to the right (ie. with lxx2). So it is actually equivalent to
val lxx3 = lxx2.::(lxx1)
instead of this,
val lxx3 = lxx1.::(lxx2)

Scala placeholder syntax

There is something that I can't quite understand hope someone can shed some light..
I have Seq[String]
val strDeps: Seq[String] = ...
and I tried to sort it on the reverse of the using the sortWith method and I get the following error.
scala> print(strDeps.sortWith(_.reverse.compareTo(_.reverse) < 0) mkString ("\n"))
<console>:15: error: wrong number of parameters; expected = 2
print(strDeps.sortWith(_.reverse.compareTo(_.reverse) < 0) mkString ("\n"))
^
But when I try sort it without doing a reverse it works fine.
scala> print(strDeps.sortWith(_.compareTo(_) < 0) mkString ("\n"))
// this is fine
Also it works fine without the placeholder syntax
scala> print(strDeps.sortWith((a,b) => a.reverse.compareTo(b.reverse) < 0) mkString ("\n"))
// this works fine too
_ expands only to the smallest possible scope.
The inner _.reverse part is already interpreted as x => x.reverse therefore the parameter is missing inside sortWith.
compareTo(_)
Is a partially applied method. It just means "compareTo, but without applying the first parameter". Note that _ is not a parameter. Rather, it indicates the absence of a parameter.
compareTo(_.reverse)
Is a method taking an anonymous function as parameter, the parameter being _.reverse. That translates to x => x.reverse.

Scala map of function using "_"

Why is it that (in the Scala REPL) I can write, for example,
def double(d: Int) = 2*d
(0 until 10).zipWithIndex.map(i => double(i._1))
or just
(0 until 10).zipWithIndex.map(_._1)
yet I can't write
(0 until 10).zipWithIndex.map(double(_._1))
error: missing parameter type for expanded function ((x$1) => x$1._1) (0 until 10).zipWithIndex.map(double(_._1))
?
Scala tries to expand _._1 inside double. So, it thinks you want to have
(0 until 10).zipWithIndex.map(double(i => i._1))
However, it also sees that i => i._1 does not really fit into one of double’s argument types, so it complains and asks you to give a type hint to help the compiler. In this case, though, there cannot be a correct type definition, so the error message is kind of wrong there.