I want to pass a function to map() which need to use additional data (for example data passed as arguments to the scala program).
For example:
I have a list:
val myList = List(1,2,3,4,5)
and a multiplier value is passed as command line argument.
val multiplier = args(0) // In this example, let it be 2
and I have a function
def multiply(a: Int, b: Int) = a*b
Now I want to perform map() on my List as below:
myList.map(multiply)
Of course this doesn't work because, map expects only one argument (which in this case is element of list).
Please help me how can pass functions to map which use additional arguments.
You can accomplish this with currying
def multiply(a: Int)(b: Int) = a*b
myList.map(multiply(multiplier))
Or, if multiply isn't your method:
val multiplyCurried = Function.curried(multiply _)
myList.map(multiplyCurried(multiplier))
Related
I have the following method:
def m(a: String*) = { // ... }
I'm wondering what the use is of the asterisk (*) symbol in this syntax? I'm obviously new to Scala. I googled but am probably googling the wrong thing. Any help is appreciated.
Cheers!
Its called as "var args" (variable arguments).
def concat(strs: String*): String = strs.foldLeft("")(_ ++ _)
Scala REPL
scala> def concat(strs: String*): String = strs.foldLeft("")(_ ++ _)
concat: (strs: String*)String
scala> concat()
res6: String = ""
scala> concat("foo")
res7: String = foo
scala> concat("foo", " ", "bar")
res8: String = foo bar
This is called a repeated parameter (see Section 4.6.3 of the Scala Language Specification).
Repeated Parameters allow a method to take an unspecified number of arguments of the same type T, which are accessible inside the method body bound to a parameter of type Seq[T].
In your case, inside the method m, the parameter a will be bound to a Seq[String].
That's the syntax to define a method that take a variable number of arguments.
Your m method can take 0, 1 or more arguments and these are all valid invocations:
m()
m("hello")
m("hello", "world")
You can also pass a collection to that method if you use the appropriate type hint:
val words = Seq("hello", "world")
m(words: _*)
You can play around with this code here on Scastie (where I implemented m as the concatenation of the input strings).
I was wondering how it works if I want to defining a function that takes one or more parameters and a callable (a function), and why the annotation is like this.
I will take the code from this answer as example:
// Returning T, throwing the exception on failure
#annotation.tailrec
final def retry[T](n: Int)(fn: => T): T = {
util.Try { fn } match {
case util.Success(x) => x
case _ if n > 1 => retry(n - 1)(fn)
case util.Failure(e) => throw e
}
}
In this function there are a few interesting things:
The annotation tailrec.
Generic type function retry[T]
Parameter int
callable fn
My question is on point 4. Why and how the definition of this function takes two round brackets. If you want to pass a callable function to any function should you always use a round brackets next to the "list" of optional parameter? Why not put together with the parameters?
Thank you in advance
You can have multiple parameter lists in function declaration. It is mostly the same as merging all the parameters into one list (def foo(a: Int)(b: Int) is more or less equivalent to def foo(a: Int, b: Int)) with a few differences:
You can reference parameters from previous list(s) in declaration: def foo(a : Int, b: Int = a + 1) does not work, but def foo(a: Int)(b: Int = a +1) does.
Type parameters can be inferred between parameter lists: def foo[T](x: T, f: T => String): String ; foo(1, _.toString) doesn't work (you'd have to write foo[Int](1, _.toString), but def foo[T](x: T)(f: T => String); foo(1)(_.toString) does.
You can only declare the entire list as implicit, so, multiple lists are helpful when you need some parameters to be implicit, and not the others: def foo(a: Int)(implicit b: Configuration)
Then, there are some syntactical advantages - things you could do with the single list, but they'd just look uglier:
Currying:
def foo(a: Int)(b: Int): String
val bar: Int => String = foo(1)
You could write this with the single list too, but it wouldn't look as nice:
def foo(a: Int, b: Int): String
val bar: Int => String = foo(1, _)
Finally, to your question:
def retry[T](n: Int)(f: => T)
is nice, because parenthesis are optional around lists with just a single argument. So, this lets you write things like
retry(3) {
val c = createConnection
doStuff(c)
closeConnection(c)
}
which would look a lot uglier if f was merged into the same list.
Also, currying is useful:
val transformer = retry[Int](3)
Seq(1,2,3).map { n => transformer(n + 1) }
Seq(4,5,6).map { n => transformer(n * 2) }
To be honest you don't have to use multiple parameter lists in order to pass function as an argument. E.g.
def pass(string: String, fn: String => Unit): Unit = fn(string)
would totally work. However, how would you call it?
pass("test", s => println(s))
Some would find it clumsy. You would rather want to pass it like:
pass("test")(s => println(s))
or even
pass("test") { s =>
println(s)
}
to make it look as if function is a block appended to the pass called with one parameter.
With single parameter list you will be forced to write it like:
pass("test", println)
pass("test", s => println(s))
pass("test", { s => println(s) })
With last parameter curried you just get more comfortable syntax. In languages like Haskell, where currying happens automatically, you don't have to bother with syntactic design decisions like this one. Unfortunately Scala requires that you made these decisions explicitly.
If you want to pass a callable function to any function should you
always use a round brackets next to the "list" of optional parameter?
Why not put together with the parameters?
There is no such obligation, it's (mostly) a matter of style. IMO, it also leads to cleaner syntax. With two parameter lists, where the second one is the function yielding the result, we can call the retry method:
val res: Try[Int] retry(3) {
42
}
Instead, of we used a single parameter list, our method call would look like this:
val res: Try[Int] = retry(3, () => {
42
})
I find the first syntax cleaner, which also allows you to use retry as a curried method when only supplying the first parameter list
However, if we think of a more advanced use case, Scala type inference works between parameter lists, not inside them. That means that if we have a method:
def mapFun[T, U](xs: List[T])(f: T => U): List[U] = ???
We would be able to call our method without specifying the type of T or U at the call site:
val res: List[Int] = mapFun(List.empty[Int])(i => i + 1)
But if we used a single parameter list,
def mapFun2[T, U](xs: List[T], f: T => U): List[U] = ???
This won't compile:
val res2 = mapFun2(List.empty[Int], i => i + 1)
Instead, we'd need to write:
val res2 = mapFun2[Int, Int](List.empty[Int], i => i + 1)
To aid the compiler at choosing the right types.
Lets say we have a function def fun(x: X): X => Y and we pass this function as a parameter to another function using fun _ instead of just fun. I understand that fun _ is actually a function value, while fun refers to a function definition.
For example let:
val a = List(1,2,3,4)
def fun(x: Int) = {println(x); x + 1}
Then Running:
//This line works
a.map(fun _)
//This one also works, even though "fun" is not a function value
a.map(fun)
They have the same output:
1
2
3
4
resX: List[Int] = List(2, 3, 4, 5)
For the most part they seem to work the same, are there any examples in which the function value is not equivalent to the function definition?
In the signature of map, you can see that it's expecting a
"function" to apply to each element
But in your code, fun is a regular method in a class. So when you do:
a.map(fun _)
you are explicitly asking for eta-expansion. When you do:
a.map(fun)
you are implicitly asking for eta-expansion.
Because fun is a "method", and is being used in a place where a Function type is expected, it's automagically converted to that type. Basically to something like:
new Function1[Int, Int] {
def apply(x: Int): Int = fun(x)
}
This transformation converting the name fun to a Function is called eta-expansion. See documentation for details.
Unfortunately, there are various ways of doing what you're doing - a.map(fun), a.map(fun _), a.map(fun(_)) and a.map(x => fun(x)). This is one of those frequent scenarios in Scala where you can explicitly do something yourself, or explicitly ask the compiler to do it for you, or just let the compiler do it implicitly. They can have different behaviors because of implicits and it can be a major source of confusion. Also, _ is heavily overloaded in the language, only adding to the confusion. So I use implicit behavior sparingly in general.
As others have pointed out in the comments, you need to use the fun _ syntax (which performs an eta expansion) when you need a value (methods have no value by themselves). Within the context of a map (or other functional contexts) an eta expansion is performed on the method implicitly. There are some cases where the eta expansion must be triggered manually.
As a concrete example of where an explicit eta expansion is needed, consider this valid snippet:
def f1(x: Int): Int = 2*x
def f2(x: Int): Int = 3*x
val fList1 = List(f1 _, f2 _)
fList1.map(_(2)) // List(4, 6)
as opposed to this invalid snippet.
val fList2 = List(f1, f2)
Having an implicit value and function defined as follows
implicit val v = 0
def function(implicit v: Int): Map[String, String] = Map("key" -> "value")
I can do
function.get("key") // res0: Option[String] = Some(value)
function(v)("key") // res0: String = value
but the following doesn't compile
function("key")
So how can I in one go access a map using parentheses and pass implicit parameter?
Here are your options:
scala> function.apply("key")
res6: String = value
scala> function(implicitly)("key")
res7: String = value
As compiler can't know if you want to pass an implicit parameter explicitly or call apply method, designers decided it will mean passing the implicit parameter.
You can either give up on using the syntactic sugar and just use apply that will resolve ambiguity or you can pass the parameter explicitly, but let the compiler find the value.
Give the following scenario:
def add(a: Int, b: Int): Int = a + b
def f1(adder: () => Int) = adder()
f1(add(1,2) _) // Does **NOT** compile, because add seems to be already executed
f1(() => add(1,2)) // This works, but seems to be ugly
Is there any way to make it work with the underscore?
You could make it work without the underscore by using a by-name parameter:
scala> def f2(adder: => Int) = adder
f2: (adder: => Int)Int
scala> f2(add(1,2))
res0: Int = 3
The problem with your 3rd line is that f1 needs a function that is called with empty params. A by-name parameter lets you pass in any arbitrary expression that results in the given type, and doesn't evaluate it until you use it within the method body. If you want to use a by-name argument in multiple places within the body of the method, but don't want it reevaluated, you can cache it by assigning it to a lazy val.