Invoke method based on list - scala

I have object in scala, where I have defined functions. I have Seq where all the functions are listed as the elements as below:
object ABC {
def abc(a: Int, b: Int): Int = a+b
def pqr(p: Int, q: Int): Int = p - q
val listFunction: Seq[(Int, Int) => Int] = Seq(abc, pqr)
}
Now, I want to call the list which I defined as string and execute all the functions inside it, by taking the parameters. Similar to the below:
val listName = "listFunction"
val method = example.ABC.getClass.getMethod(listName,1,2)
Can someone help me, how to invoke the listFunction list and execute all the functions inside it.

To call the methods do this:
val result: Seq[Int] = ABC.listFunction.map(_(1, 2))
This calls each function in turn and puts the result in a new Seq.
If you want multiple lists indexed by name, use a Map like this:
object ABC {
def abc(a: Int, b: Int): Int = a+b
def pqr(p: Int, q: Int): Int = p - q
private val functions = Map(
"listFunction" -> Seq(abc _, pqr _),
"listReverse" -> Seq(pqr _, abc _),
)
def apply(name: String) = functions(name)
}
val listName = "listFunction"
val result: Seq[Int] = ABC(listName).map(_(1, 2))

Try
val listName = "listFunction"
example.ABC.getClass.getMethod(listName).invoke(example.ABC).asInstanceOf[Seq[(Int, Int) => Int]].map(_.apply(1, 2)) // List(3, -1)

Related

Execute functions in a List

I have Object in scala in which I have defined some functions.
Object Sample {
val listFunction = Seq(func1(a,b),func2(p,q))
def func1(a: Int,b : Int) : Int ={
val c = a+b
c
}
def func2(p: Int,q : Int) : Int ={
val d = p+q
}
}
def main(args: Array[String]): Unit = {
//Want to call the list and execute the functions
ListFunction
}
How to call the list in main method and execute it?
Given
def func1(a: Int, b: Int): Int = a + b
def func2(p: Int, q: Int): Int = p + q
Consider the difference between
val x: Int = func1(2, 3) // applied function
val f: (Int, Int) => Int = func1 // function as value
So you have to use functions as values as you pass them to the sequence like so
val listFunction: Seq[(Int, Int) => Int] = Seq(func1, func2)
and then map over the list to apply the functions
listFunction.map(f => f.apply(2, 3))
listFunction.map(f => f(2, 3))
listFunction.map(_(2, 3))
scastie

Why scala can't pass a function name directly to a val?

I have this scala code:
object C extends App{
def sum(a:Int,b:Int,c:Int)=a+b+c
//val d=sum
val d=sum _
println(d(1,2,3))
}
I have to write sum _,not sum
but In f#,I can write this:
let sum a b c=a+b+c
let d=sum
[<EntryPoint>]
let main argv =
printfn "%A" (d 1 2 3)
0 // return an integer exit code
why in scala I can't just write
val d=sum
Scala has
methods (by default def is a method) and
functions
And they are not same.
Taking java methods as example, you can not assign methods to a variable without evaluating the method. But you can do that with function and to achieve that in scala define sum as function.
scala> def sum: (Int, Int, Int) => Int = (a, b, c) => a + b + c
sum: (Int, Int, Int) => Int
scala> val sumVal = sum
sumVal: (Int, Int, Int) => Int = $$Lambda$912/0x0000000801667840#716f94c1
scala> sumVal(1, 2, 3)
res1: Int = 6
Longer version of defining a function is,
scala> def sum = new Function3[Int, Int, Int, Int] {
| def apply(a: Int, b: Int, c: Int): Int = a +b + c
| }
sum: (Int, Int, Int) => Int
scala> val sumVal = sum
sumVal: (Int, Int, Int) => Int = <function3>
scala> sumVal(1, 2, 3)
res2: Int = 6

Why does this partial application not compile?

The following:
val add = (a: Int, b: Int) => a + b
gets converted to:
object add extends Function2[Int, Int, Int] {
def apply(a: Int, b: Int) = a + b
}
while
val a1 = add(_: Int, 3)
gets converted to:
object a1 extends Function1[Int, Int] {
def apply(x: Int): Int = {
add(x, 3)
}
}
But when I do:
scala> val a2 = add _
a2: () => (Int, Int) => Int = <function0>
And then call a2, it throws an error:
scala> a2(1, 2)
<console>:11: error: too many arguments for method apply: ()(Int, Int) => Int in trait Function0
a2(1, 2)
^
Why is this? Why does the following work?
a2()(1, 2)
add is already a Function2[Int, Int, Int]. If you want a2 to have the same type, then a simple assignment will suffice.
scala> val a2 = add
a2: (Int, Int) => Int = <function2>
scala> a2(1, 2)
res3: Int = 3
What you're thinking of is eta-expansion of a method into a function. If we had:
def add(a: Int, b: Int): Int = a + b
Then, we would use add _ to get the eta-expansion to assign to a value.
scala> def a2 = add _
a2: (Int, Int) => Int
scala> a2(1, 2)
res4: Int = 3
But add is already a function, so the underscore has a different meaning. add is now a value and not a method. Since add is a value, it is like a parameter-less method that returns a Function2[Int, Int, Int]. And if we try to get the eta-expansion of that, we get () => Function2[Int, Int, Int].
Consider a simpler example where we have a simple val a = 1. a is essentially the same as a parameter-less method that returns 1 (def a = 1). If I try to obtain the eta-expansion, I will get () => Int.
scala> val a = 1
a: Int = 1
scala> val a2 = a _
a2: () => Int = <function0>

Scala tuple extraction in function declaration

Given for instance a Tuple2 of the form
type Duple = (String,Int)
this function errs to extract and label the duple's items in the arguments,
def f( (s,n): Duple ): String = s*n
However this works,
def f( d: Duple ): String = {
val (s,n) = d
s*n
}
Is there a shorter form to extract and label a tuple's items in a function than this declarative approach ?
Start with a regular 2 arg function:
scala> val f: (String, Int) => String = (a, b) => a * b
f: (String, Int) => String = <function2>
convert it to single arg function that accepts tuples:
scala> val tf = f tupled
tf: ((String, Int)) => String = <function1>
call it with a tuple arg:
scala> tf("a" -> 2)
res0: String = aa
or if you going the opposite direction:
start with a function that takes a tuple:
scala> tf
res2: ((String, Int)) => String = <function1>
convert it to function that takes 2 args:
scala> val uf = Function.untupled(tf)
uf: (String, Int) => String = <function2>
call it with 2 args:
scala> uf("b", 3)
res3: String = bbb
def f(d: Duple): String = d._1 * d._2
def f(d: Duple): String = d match { case (x, y) => x * y }

Printing out a function's name in println()?

I have an array of functions. How can I get the names to print in a println() function? In the code below I just get this output:
<function2>
<function2>
<function2>
Assume that in my real code I have a lot more functions with more descriptive names.
def printNames() {
def f1(x: Int, y: Int): Int = x + y
def f2(x: Int, y: Int): Int = x - y
def f3(x: Int, y: Int): Int = x * y
val fnList = Array(f1 _, f2 _, f3 _)
for (f <- fnList) {
println(f.toString());
}
}
Functions in Scala don't have descriptive names any more than Ints or Lists have descriptive names; you could make a case for toString giving a representation of its value, but that wouldn't be a name.
You could, however, extend Function2 thus:
object f1 extends Function2[Int, Int, Int] {
def apply(a: Int, b: Int) = a + b
override def toString = "f1"
}
which will act as you want.
Or more generally
class NamedFunction2[T1,T2,R](name: String, f: Function2[T1,T2,R])
extends Function2[T1,T2,R] {
def apply(a: T1, b: T2): R = f.apply(a, b)
override def toString = name
}
then use as
val f1 = new NamedFunction2[Int, Int, Int]("f1", _ + _)
etc.
You can't; the name is lost during conversion from a method to a Function2.