I am trying to sum a list using fold in the Scala interpreter, but it keeps giving me a strange error. When I type this:
val list = List(1,2,3)
(list :\ 0)(+)
I expect to get 6. However, the interpreter says
error: illegal start of simple expression
(list :\ 0)(+)
^
If I define my own function
def plus(a: Int, b: Int) = a+b
and call
(list :\ 0)(plus)
I do in fact get 6.
I'm sure I'm missing something really simple here, but I can't figure it out, so any help is much appreciated.
The plus operator by itself is not a function it is a symbol and has no type. What you are looking for is the following
val list = List(1,2,3)
(list :\ 0)(_+_)
The _+_ is shorthand for an anonymous function that takes two parameters and calls the + method on the first parameter passing in the second.
Try this:
(list :\ 0)(_ + _)
You need to use the wildcards to show the Scala compiler that you want to call the "+" method on first of the arguments instead of using the Tuple2 as an argument to a function itself.
Related
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.
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
1 to 5 foldRight (0)(x:Int, y:Int => x+y)
I am trying to add all the values from right to left with 0 as the initial parameter. I get the following error
Int(0) does not take parameters
Can anyone explain to me what this error even means?
Thanks.
It's just the parser getting "confused", so it's trying to apply (x: Int, y: Int ...) as argument of (0).
Specifically, what you're using is a scala syntactic feature that allows to use
a.f(b)
as
a f b
This works with any method that has a single parameter. However when your method has multiple parameter lists (like foldRight), you have to use extra care.
This is what the parser sees
1 to 5 foldRight (0)(x: Int, y: Int => x + y)
|__a__| |___f___| |____________b_____________|
So when evaluating b, it treats 0 as a function with (x: Int, ...) as an argument.
Clearly this can't work, because "Int(0) does not take parameters".
Instead, you can use
(1 to 5).foldRight(0)((x,y) => x + y)
or even
(1 to 5).foldRight(0)(_ + _)
There are two things wrong with your code. The first is that you need to use brackets around 1 to 5, the second is the syntax of your anonymous function. You need brackets around the parameters there.
(1 to 5).foldRight(0)((x,y) => x + y)
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.
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.