I'm currently learning Scala, and I just wondered at fold-left.
Since fold-left is curried, you should be able to get a partially applied function(PAF) with a first parameter as below.
(0 /: List(1, 2, 3)) _
But actually, I've got an error.
<console>:8: error: missing arguments for method /: in trait TraversableOnce;
follow this method with `_' if you want to treat it as a partially applied function
Then I tried same thing by fold-right such as below
(List(1, 2, 3) :\ 0) _
In this way, it went correctly, and I could get a PAF such as ((Int, Int) => Int) => Int
I know I can get a PAF by using foldLeft method, but I wonder whether it is possible to express it with '/:' or not.
The underscore syntax does not work well with right-associative methods that take multiple parameter lists. Here are the options I see:
Declare a variable type:
val x: ((Int, Int) => Int) => Int = 0 /: List(1, 2, 3)
Similarly, use type ascription:
val x = (0 /: List(1,2,3)) : ((Int, Int) => Int) => Int
Use the postfix notation:
val x = List(1,2,3)./:(0) _
Use the foldLeft synonym:
val x = List(1,2,3).foldLeft(0) _
I played around with it, and couldn't find a configuration that works.
There's always the more explicit:
val f = List(1,2,3,4,5).foldLeft(0)_
Which is arguably neater. I'll keep poking around though.
Edit:
There's this:
val f2 = (0 /: List(1,2,3,4,5))(_: (Int,Int) => Int)
val x = f2(_+_)
But that's getting pretty ugly. Without the type annotation, it complains. That's the best I could do though.
Related
I'm trying to sort a list by how close the entries of a list are to num.
I decided to try use sortWith, but the following snippet:
list.sortWith(math.abs(_ - num) < math.abs(_ - num))
failed with missing parameter type for _ in scala.
list is of type List[Int].
Following the other threads, I know that _ is somehow type ambiguous, but I'm not sure why, (and why the following snippet is not type ambiguous):
scala> val sortedDudes = dudes.sortWith(_.name < _.name)
sortedDudes: Array[Person] = Array(Al, Paul, Tyler)
(Source)
def foo = {
val num = 2
val list: List[Int] = List(1, 2)
list.sortWith((a, b) => math.abs(a - num) < math.abs(b - num))
}
work perfectly. It's because scala trying get _ from math.abs, not sortWith
In Scala, _ can be used in a variety of different situations to mean different things. The answers on this question should help clarify a few of them.
Going back to the question, it seems the OP is trying to use _ for parameter replacement. Consider the following example
List(1,2,5,7).filter(_ > 4)
Here filter takes a function of type A => Unit, so the above is shorthand for
List(1,2,5,7).filter(x => x > 4)
The underscore can stand for more than one parameter, but it must be used to refer to each parameter exactly once. This is why the sortedDudes snippet in the OP works. Therefore the following is legal.
List(1,2,5,7).reduce(_ + _)
which is shorthand for
List(1,2,5,7).reduce((a,b) => a + b)
I think the problem with the original snippet is that the compiler cannot unambiguously parse it into something of type (A, A) => Boolean as required by the sortWith method. We can give the compiler a little help as follows.
scala> def op(int: Int, num: Int) = math.abs(int - num)
op: (int: Int, num: Int)Int
scala> List(1,7,5,10).sortWith(op(_, 5) < op(_, 5))
res0: List[Int] = List(5, 7, 1, 10)
I have a mapper function defined as such:
def foo(x:Int) = if (x>2) x*2
the type signature of this method being Int => AnyVal. Now if I map this function over a list of integers:
scala> List(-1,3,-4,0,5).map(foo)
res0: List[AnyVal] = List((), 6, (), (), 10)
I need a way of filtering out the Units from the Ints like so:
scala> res0.filter(_.isInstanceOf[Int]).map(_.asInstanceOf[Int])
res1: List[Int] = List(6, 10)
Everything seems concisely expressed until I have to do the filter-map on res0 to extract the values I care about. I could use matchers or an if-else in foo to always ensure I return an Int but I'd still need to filter the unwanted values resulting from the map operation.
Can any of the well-seasoned Scala developers reading this provide some additional insight into what's good or bad about this approach especially as my collection grows large (e.g. maybe this collection is a distributed Spark RDD)? Are there more idiomatic ways of doing this functionally?
In this case I suggest you to use collect with PartialFunction, if you need to drop all ints that are smaller than 2
val foo: PartialFunction[Int, Int] = {
case x if x > 2 => x*2
}
println(List(-1,3,-4,0,5).collect(foo))
Your original foo has type Int => AnyVal, because scalac transforms it in something like
def foo(x: Int) = if (x > 2) x*2 else () // () === Unit
and common super type for Int and Unit is AnyVal
I'm taking my first interesting steps (non-hello-world level) with Scala (2.9.1) and I'm stuck trying to understand a very uninformative error message.
It goes much like this:
error: type mismatch;
found : (Int, Array[InputEntry]) => (Int, Double)
required: (Int, Array[InputEntry]) => ?
entries.groupBy(grouper).map((k: Int, ies: Array[InputEntry]) => (k, doMyStuff(ies)))
As you can guess process in this snippet is supposed to be where some processing goes on, and it's actually a well defined function with signature Array[InputEntry] => Double.
Grouper's signature, instead, is Array[InputEntry] => Int.
I've tried to extract a function and replace the lambda but it was useless, and I'm stuck trying to understand the question mark in the error...
Any ideas?
Edit: I should clarify that InputEntry is a class I've defined, but for the sake of this example it seems to me like it's hardly relevant.
This looks like the problem:
.map((k: Int, ies: Array[InputEntry]) => (k, doMyStuff(ies)))
You need to use a case statement to unapply the params and assign them to local variables. You also need to use {} instead of () because it is an anonymous function now.
entries.groupBy(grouper).map{case (k, ies) => (k, doMyStuff(ies))}
Here's a more simple example.
scala> val x = List(("a",1),("b",2))
x: List[(java.lang.String, Int)] = List((a,1), (b,2))
scala> x.map{ case (str, num) => num }
res5: List[Int] = List(1, 2)
If you don't want to use a case statement, you have to keep the tuple as a single variable.
scala> x.map(tuple => tuple._2)
res6: List[Int] = List(1, 2)
I'm trying to understand the advantages of currying over partial applications in Scala. Please consider the following code:
def sum(f: Int => Int) = (a: Int, b: Int) => f(a) + f(b)
def sum2(f: Int => Int, a: Int, b: Int): Int = f(a) + f(b)
def sum3(f: Int => Int)(a: Int, b: Int): Int = f(a) + f(b)
val ho = sum({identity})
val partial = sum2({ identity }, _, _)
val currying = sum3({ identity })
val a = currying(2, 2)
val b = partial(2, 2)
val c = ho(2, 2)
So, if I can calculate partially applied function that easy, what are the advantages of currying?
Currying is mostly used if the second parameter section is a function or a by name parameter. This has two advantages. First, the function argument can then look like a code block enclosed in braces. E.g.
using(new File(name)) { f =>
...
}
This reads better than the uncurried alternative:
using(new File(name), f => {
...
})
Second, and more importantly, type inference can usually figure out the function's parameter type, so it does not have to be given at the call site.
For instance, if I define a max function over lists like this:
def max[T](xs: List[T])(compare: (T, T) => Boolean)
I can call it like this:
max(List(1, -3, 43, 0)) ((x, y) => x < y)
or even shorter:
max(List(1, -3, 43, 0)) (_ < _)
If I defined max as an uncurried function, this would not work, I'd have to call it like this:
max(List(1, -3, 43, 0), (x: Int, y: Int) => x < y)
If the last parameter is not a function or by-name parameter, I would not advise currying. Scala's _ notatation is amost as lightweight, more flexible, and IMO clearer.
I think it becomes clearer if you invert your curried example:
def sum4(a: Int, b: Int)(f: Int => Int): Int = f(a) + f(b)
val d = sum4(2, 2) { x =>
x * x
}
It is more of an optical effect but you don’t need to use any parentheses around the whole expression. Of course you can achieve the same result using partial application or by creating a helper method to invert the arguments, sure. The point is, that you don’t have to do all of this if you start with a curried method in the first place. In that sense currying is more of an API and syntax sugar thing. It is not expected that you use
val partial_sum4 = sum4(2, 2)
anywhere in your code or that this is in any way especially meaningful to do. It is just that you get a nicely looking expression easily.
(Well, and there are some advantages with respect to type inference…)
I'm not sure why this doesn't work:
scala> case class Loader(n: String, x: String, l: List[String])
scala> val m: Map[String, (List[String])=>Loader] =
| Map("x" -> Loader("x", "x1", _:List[String]))
<console>:8: error: type mismatch;
found : (List[String]) => (java.lang.String, Loader)
required: (String, (List[String]) => Loader)
Map("x" -> Loader("x", "x1", _:List[String]))
but this does?
scala> Loader("t", "x", _:List[String])
res7: (List[String]) => Loader = function1>
scala> val m = Map("x" -> res7)
m: scala.collection.immutable.Map[java.lang.String,(List[String]) => Loader] =
Map((String,function1>))
One more victim of the overload of _ in Scala. Consider this:
f(_, 5) + 1 // Partial function application
f(_ + 1, 5) // Closure
In the first case, _ is replacing the entire parameter. In this case, it stands for a partial application of f. In practice, it's equivalent to x => f(x, 5) + 1, as the whole expression that contains f is turned into a closure.
In the second case, _ is part of an expression. In this case, the whole expression is turned into a closure, up to any expression delimiter -- by which I mean that if the expression is nested inside another, only the inner expression is turned into a closure. In practice, it is equivalent to f(x => x + 1, 5).
The parser was not sure where to put the beginning of the anonymous function. Sometimes you can solve this by adding another pair of parentheses (though not always):
val m: Map[String, (List[String])=>Loader] =
Map("x" -> (Loader("x", "x1", _:List[String])))
I don’t see any ambiguities here, so it might just not have been smart enough to figure it out. I think, the parser overlooked the possibility to have an anonymous function just after the -> (which also is a library construct and uses implicit magic and all the wicket stuff which makes the little parser’s mind loop).
When you write it as an explicit tuple, it’ll work fine.
val m: Map[String, (List[String])=>Loader] =
Map(("x", Loader("x", "x1", _:List[String])))