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

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.

Related

Compiler generated function class in Scala

I understand that when I do this:
val sum = (a: Int, b: Int) => a + b
Scala compiler turns it into this:
val sum = new Function2[Int, Int, Int] {
def apply(a: Int, b: Int): Int = a + b
}
So Function2 is a class made for Int based operations.We use [] to convey that operations in this class involves(input,output,body) only Int.
Isn't only one Int entry in [] sufficient to convey this. But we have 3 Int entries in [].
Nothing in Function2 says that it is "made for Int based operations".
Function2[X, Y, Z] is a class for generic functions that that take two inputs of type X and Y and return a Z.
Specifying a single Int is obviously not sufficient, because Function2 requires exactly three type parameters.
How would you otherwise be able to tell a difference between a
Function2[Int, Int, Int]
and a
Function2[Int, Double, String]
as for example in
val sum = (a: Int, b: Double) => a + " -> " + b
which is syntactic sugar for
val sum = new Function2[Int, Double, String] {
def apply(a: Int, b: Double) = a + " -> " + b
}
?
If you often use Function2[T, T, T] for the same type T, you can define a type alias:
type BinOp[T] = Function2[T, T, T]
or shorter:
type BinOp[T] = (T, T) => T

How to reduce the unwanted type parameter in a generic method?

I want to implement some generic math functions with some flexible.
e.g. a function named meandot which declared as something like
object Calc {
def meandot[..](xs: Array[Left], ys: Array[Right])(implicit ..): Result
}
where meandot(xs, ys) = sum(x*y for x, y in zip(xs, ys)) / length
When I invoke the meandot without specialized type parameter, it should return a value with default type. e.g.
scala> Calc.meandot(Array(1, 2), Array(1, 1))
res0: Int = 1
If I invoke the meandot with specialized type parameter, it can return a proper value.
scala> Calc.meandot[Int, Int, Double](Array(1, 2), Array(1, 1))
res1: Double = 1.5
However, the first two type parameters in above are redundant. The only type I need to specialized is the return type. I want to invoke it simplified as
scala> Calc.meandot2(Array(1, 2), Array(1, 1))
res2: Int = 1
scala> Calc.meandot2[Double](Array(1, 2), Array(1, 1))
res3: Double = 1.5
And I found a way to implement it as following code, which using a proxy class MeanDotImp. But it seems not so elegant. So I wonder if there is any better solution to reduce the unwanted type parameter in a generic method?
trait Times[L, R, N] {
def times(x: L, y: R): N
}
trait Num[N] {
def zero: N = fromInt(0)
def one: N = fromInt(1)
def fromInt(i: Int): N
def plus(x: N, y: N): N
def div(x: N, y: N): N
}
abstract class LowTimesImplicits {
implicit val IID: Times[Int, Int, Double] = new Times[Int, Int, Double] {
def times(x: Int, y: Int): Double = x * y
}
}
object Times extends LowTimesImplicits {
implicit val III: Times[Int, Int, Int] = new Times[Int, Int, Int] {
def times(x: Int, y: Int): Int = x * y
}
}
object Num {
implicit val INT: Num[Int] = new Num[Int] {
def fromInt(i: Int): Int = i
def plus(x: Int, y: Int): Int = x + y
def div(x: Int, y: Int): Int = x / y
}
implicit val DOU: Num[Double] = new Num[Double] {
def fromInt(i: Int): Double = i
def plus(x: Double, y: Double): Double = x + y
def div(x: Double, y: Double): Double = x / y
}
}
object Calc {
def meandot[L, R, N](xs: Array[L], ys: Array[R])
(implicit t: Times[L, R, N], n: Num[N]): N = {
val total = (xs, ys).zipped.foldLeft(n.zero){
case(r, (x, y)) => n.plus(r, t.times(x, y))
}
n.div(total, n.fromInt(xs.length))
}
implicit class MeanDotImp[L, R](val marker: Calc.type) {
def meandot2[N](xs: Array[L], ys: Array[R])
(implicit t: Times[L, R, N], n: Num[N]): N = {
val total = (xs, ys).zipped.foldLeft(n.zero){
case(r, (x, y)) => n.plus(r, t.times(x, y))
}
n.div(total, n.fromInt(xs.length))
}
}
}
An alternative solution is similar to yours, but is a bit more straightforward: it first fixes the type parameter that you want to be able to set and then infers the other two. To achieve that we can declare a class with apply method:
class meandot[N] {
def apply[L, R](xs: Array[L], ys: Array[R])
(implicit t: Times[L, R, N], n: Num[N]): N = ??? // your implementation
}
Now, to avoid writing new meandot, we can define a method which just instantiates this class:
object Calc {
def meandot[N]: meandot[N] = new meandot[N]
}
Elegance of this approach is arguable, but it's quite simple and doesn't involve implicits. Here's a usage demo:
scala> Calc.meandot(Array(1,2,3), Array(4,5,6))
res0: Int = 10
scala> Calc.meandot[Double](Array(1,2,3), Array(4,5,6))
res1: Double = 10.666666666666666

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 Case Class with Different Argument Types

I want to write a case class that can take in a function that has one or more Ints as its arguments. For instance, these would be valid functions:
def foo(x: Int): String = "foo"
def bar(x: Int, y: Int): String = "bar"
def foobar(x: Int, y: Int, z: Int): String = "foobar"
but this would not:
def nonExample():String = "no"
The problem is that I can't get the right argument type for my case class.
case class Mine(function: ???) {}
I've tried:
case class Mine(function: (Int*) => String)
and this didn't work since (Int*) is a sequence of Ints. I also tried using Function and Function1, but that didn't work either. Any ideas (or alternatives if this isn't possible in Scala)?
Edit: As Didier Dupont mentioned, Mine also needs to know how many arguments the method requires. Above I oversimplified Mine. It will also take another argument that tells about the function passed in. Based on that, it'll decide how many parameters to pass into the function. But other than that chunk of code, everything else in Mine operates the same regardless of the function.
I would recomend next solution (it has some disadvantages, but generaly it satisfy your needs)
sealed trait FuncRes[F] {
def resolve : F
}
object FuncRes {
implicit def func1[T1, R](f : T1 => R) =
new FuncRes[(T1 => R)] {
def resolve = f
}
implicit def func2[T1, T2, R](f : (T1, T2) => R) =
new FuncRes[((T1, T2) => R)] {
def resolve = f
}
implicit def func3[T1, T2, T3, R](f : (T1, T2, T3) => R) =
new FuncRes[((T1, T2, T3) => R)] {
def resolve = f
}
}
case class Mine[F](private val f : FuncRes[F]) {
def func[F] = f.resolve
}
and usage example:
def foo(x: Int): String = "foo"
def bar(x: Int, y: Int): String = "bar"
def foobar(x: Int, y: Int, z: Int): String = "foobar"
val m1 = Mine(foo _)
println { m1.func(10) } // output: "foo"
val m2 = Mine(bar _)
println { m2.func(10, 20) } // output: "bar"
val m3 = Mine(foobar _)
println { m3.func(10, 20, 30) } // output: "foobar"
How about (Int, Int*) => String? You would receive the second argument as a Seq[Int].
Why not using a function Array[Int] => String? Varargs are essentially array so it should fit.

Why doesn't Function2 have an andThen method?

Why does andThen only exist for single argument functions in Scala?
The following code works:
val double = (x: Int) => x * 2
val timesFour = double andThen double
But why is there no andThen method for multi argument functions?
val multiply = (x: Int, y: Int) => x * y
val multiplyAndDouble = multiply andThen double
<console>:10: error: value andThen is not a member of (Int, Int) => Int
Surely it is trivial to add this method. Is there a reason it been omitted from the standard library?
I have just noticed it is easy to work around with the following:
val multiplyAndDouble = multiply.tupled andThen double
val res = multiplyAndDouble(1, 3) // res = 6
I can't speak as to why Function2 doesn't supply and andThen, but Scalaz defines Functor instances for functions of various arities where map is equivalent to andThen, meaning you could write
val multiplyAndDouble = multiply map double
There is a similar question here:
Scala API 2.10.*: Function2.andThen what happened to?, but there is also no answer. In my opinion it is possible. Here is working example for Scala 2.11.1:
object TestFunction2 {
def main(args: Array[String]): Unit = {
val double = (x: Int) => x * 2
val timesFour = double andThen double
println(timesFour(2)) // prints 8
val multiply = (x: Int, y: Int) => x * y
val multiplyAndDouble = multiply andThen double
println(multiplyAndDouble(1, 3)) // prints 6
}
implicit def toFunc2(function2: Function2[Int, Int, Int]): Func2[Int, Int, Int] = {
new Func2[Int, Int, Int] {
def apply(v1: Int, v2: Int): Int = function2(v1, v2)
}
}
}
trait Func2[-T1, -T2, +R] extends Function2[T1, T2, R] {
def andThen[A](g: R => A): (T1, T2) => A = { (x, y) => g(apply(x, y)) }
}
Another way to write theons's answer is to use:
val multiplyAndDouble = double compose multiply.tupled
val result = multiplyAndDouble(2, 6) // res 24