Signature of a function that takes an unkown number of inputs - scala

Try:
def big[T1, T2](func: T1 => T2) = func
def small(t1: Double, t2: Double) = (t1, t2)
big(small)
Error:
Type mismatch: Expected (NotInfered1) => NotInferedT2, actual: (Double, Double) => (Double, Double)
Same with:
def big[T1, T2](func: (T1*) => T2) = func
I believe the parameter signature for "big" should be something else that accepts a function that takes an unknown number of arguments.

Here are couple options:
1) Using tupled - converts that function to Function1 so compiler is happy (not the user though :)):
scala> def big[T1, T2](func: T1 => T2) = func
big: [T1, T2](func: T1 => T2)T1 => T2
scala> def small(t1: Double, t2: Double) = (t1, t2)
small: (t1: Double, t2: Double)(Double, Double)
scala> big(small)
<console>:10: error: type mismatch;
found : (Double, Double) => (Double, Double)
required: ? => ?
big(small)
^
scala> big(small _ tupled)
warning: there were 1 feature warning(s); re-run with -feature for details
res1: ((Double, Double)) => (Double, Double) = <function1>
2) Change the type of big to take anything that produces T:
scala> def big[T](func: => T) = func
big: [T](func: => T)T
scala> big(small _)
res3: (Double, Double) => (Double, Double) = <function2>
scala> def verysmall(t1: Int) = t1
verysmall: (t1: Int)Int
scala> big(verysmall _)
res4: Int => Int = <function1>
Note that in the first case it's a Function1 that takes a tuple and in the second case it's a Function2 that takes 2 params.
Looks like you vere looking for ( => T) syntax.

Scala does not have functions that take any arbitrary number of arguments. Methods can be variadic, e.g. def x(x: Int*), but functions must inherit from one of the Function traits, e.g. Function1, Function2, which forces them to have a definite number of parameters.
However, you can instead use functions that take a tuple:
val small = (tuple: (Double, Double)) => tuple

Related

Scala : eta expansion of function values (not methods)

After experimenting with scala's eta expansion, I came across a weird feature.
Let's define a method:
scala> def sum(a: Int, b: Int): Int = a + b
sum: (a: Int, b: Int)Int
Ok, up until now, everything is fine. Now let's assign it to a val using eta expansion:
scala> val f = sum _
f: (Int, Int) => Int = $$Lambda$1051/694580932#55638165
Now, the strange thing is coming. I can apply eta expansion again to f, and it is working (however it adds currying to my method) :
scala> val g = f _
g: () => (Int, Int) => Int = $$Lambda$1055/1351568309#5602e540
Why is this working ? I thought that eta expansion was only valid for methods.
Moreover, I noticed that this is not possible:
scala> ((a: Int, b: Int) => a + b: Int) _
<console>:12: error: _ must follow method; cannot follow (Int, Int) => Int
((a: Int, b: Int) => a + b: Int) _
^
But is it not the same as applying eta expansion to f ?
I am a bit confused and these eta expansions still hide some magic for me.
Thanks a lot !
When you write val f = sum _ at the top level of the REPL or an object/class, Scala defines an accessor method so that you can access it. Here is how Scala desugars this (via scalac -Xprint:typer on val f: (Int, Int) => Int = _ + _):
private[this] val f: (Int, Int) => Int = ((x$1: Int, x$2: Int) => x$1.+(x$2));
<stable> <accessor> def f: (Int, Int) => Int = Foo.this.f;
So, when you subsequently write val g = f _, it's doing eta-expansion on the zero-argument accessor method, which results in the behavior you see. For more verification of this, notice that, if you put the definitions in a method, you get an error:
def foo = {
val f: (Int, Int) => Int = _ + _
val g = f _ // error: _ must follow method; cannot follow (Int, Int) => Int
}
This is because accessors are only generated for fields (and top-level REPL definitions, which are treated like fields).

How does a "case" anonymous function really work in Scala?

Dеar Scala,
scala> val f1: ((Int, Int)) => Int = { case (a, b) => a + b }
f1: ((Int, Int)) => Int = <function1>
scala> val f2: (Int, Int) => Int = { case (a, b) => a + b }
f2: (Int, Int) => Int = <function2>
huh?!
scala> f1(1, 2)
res2: Int = 3
Ok...
scala> def takesIntInt2Int(fun: (Int, Int) => Int) = fun(100, 200)
takesIntInt2Int: (fun: (Int, Int) => Int)Int
scala> def takesTuple2Int(fun: ((Int, Int)) => Int) = fun(100, 200)
takesTuple2Int: (fun: ((Int, Int)) => Int)Int
scala> takesIntInt2Int(f2)
res4: Int = 300
scala> takesIntInt2Int(f1)
<console>:10: error: type mismatch;
found : ((Int, Int)) => Int
required: (Int, Int) => Int
takesIntInt2Int(f1)
^
scala> takesTuple2Int(f1)
res6: Int = 300
scala> takesTuple2Int(f2)
<console>:10: error: type mismatch;
found : (Int, Int) => Int
required: ((Int, Int)) => Int
takesTuple2Int(f2)
Right. And now, look at this!
scala> takesTuple2Int { case (a, b, c) => a + b + c }
<console>:9: error: constructor cannot be instantiated to expected type;
found : (T1, T2, T3)
required: (Int, Int)
takesTuple2Int { case (a, b, c) => a + b + c }
^
scala> takesIntInt2Int { case (a, b, c) => a + b + c }
<console>:9: error: constructor cannot be instantiated to expected type;
found : (T1, T2, T3)
required: (Int, Int)
takesIntInt2Int { case (a, b, c) => a + b + c }
Like, srsly? o_O Both result in required: (Int, Int) error.
Why then use case at all in such anonymous functions?
See section 8.5 of the Scala reference (http://www.scala-lang.org/files/archive/nightly/pdfs/ScalaReference.pdf). The expression { case (a, b) => a + b } is interpreted differently based on the expected type. In your definition of f1 it created a PartialFunction[(Int, Int), Int] which was cast to a Function1[(Int, Int), Int], i.e. ((Int, Int)) => Int whereas in the definition of f2 it created a Function2[Int, Int, Int], i.e. (Int, Int) => Int.
These two interpretations relate to the two situations where you would commonly use case in an anonymous function.
One is for writing anonymous functions that accept tuples and work on their components, as you did with f1. An example would be the function you pass to the foreach or map method on a Map, e.g. Map(1 -> 2, 3 -> 4) map { case (k, v) => k + v }.
The second is for writing an anonymous function that does a match on its sole parameter. Your f2 is doing this, but not in any useful way. An example would be the anonymous function passed to collect, e.g. List(1, -2, 3) collect { case x if x > 0 => -x }.
Note that the two can be combined, that is functions like f1 can do complex matching as well. For example, Map(1 -> 2, 3 -> 4) collect { case (k, v) if k < 2 => v }.
Edit: res2 works because of tupling. If an application doesn't type check, the compiler will try wrapping the args in a tuple before failing.
But that is tried just for applications; it's not a general conversion, as you discovered. It will not try to upgrade a value Function2[A, B, C] to Function1[(A, B), C].

Generic scala function whose input is a function of variable arity

I want to define a function f that takes another function g. We require g to take take n Doubles (for some fixed n) and return a Double. The function call f(g) should return the specific value of n.
For example, f(Math.max) = 2 since Math.sin has type (Double, Double) => Double, and f(Math.sin) = 1 since Math.sin has type Double => Double.
How can I define f using Scala generics?
I've tried several forms without success. For example:
def f[A <: Product](g: Product => Double) = {...}
This doesn't work since we cannot extract the value of n at compile time, and cannot constrain the A to contain only Double values.
There is a pattern called Magnet Pattern, created by the Spray team. It does exectly what you want
This was a good excuse for me to look into Shapeless, something I always wanted to do at some point :)
$ git clone git#github.com:milessabin/shapeless.git
...
$ cd shapeless
(1)
Shapeless provides some abstractions over arity, and especially the representation as heterogeneous list (HList). A function of arbitrary arity can be seen as FnHList (a function that takes an HList as argument).
$ sbt shapeless-core/console
scala> import shapeless._
import shapeless._
scala> def isFunction[A](fun: A)(implicit fnh: FnHLister[A]) {}
isFunction: [A](fun: A)(implicit fnh: shapeless.FnHLister[A])Unit
scala> isFunction(math.sqrt _)
scala> isFunction(math.random _)
(2)
Now let's require that the function returns a Double:
scala> def isFunReturningDouble[A](fun: A)(implicit fnh: FnHLister[A] { type Result = Double }) {}
isFunReturningDouble: [A](fun: A)(implicit fnh: shapeless.FnHLister[A]{type Result = Double})Unit
scala> isFunReturningDouble(math.sqrt _)
scala> isFunReturningDouble(math.signum _)
<console>:12: error: could not find implicit value for parameter fnh: shapeless.FnHLister[Int => Int]{type Result = Double}
isFunReturningDouble(math.signum _)
^
(3)
The LUBConstraint type class can witness the upper bound of the argument list:
scala> def isValidFun[A, B <: HList](fun: A)(implicit fnh: FnHLister[A] { type Result = Double; type Args = B }, lub: LUBConstraint[B, Double]) {}
isValidFun: [A, B <: shapeless.HList](fun: A)(implicit fnh: shapeless.FnHLister[A]{type Result = Double; type Args = B}, implicit lub: shapeless.LUBConstraint[B,Double])Unit
scala> isValidFun(math.random _)
scala> isValidFun((i: Int) => i.toDouble)
<console>:12: error: could not find implicit value for parameter lub: shapeless.LUBConstraint[B,Double]
isValidFun((i: Int) => i.toDouble)
^
(4)
Now we still need to extract the arity somehow. On the type level this would be Length which is provided for HList. To get a runtime value, another type class ToInt is needed.
Here is the final function:
import shapeless._
def doubleFunArity[A, B <: HList, C <: Nat](fun: A)(implicit
fnh: FnHLister[A] { type Result = Double; type Args = B },
lub: LUBConstraint[B, Double],
len: Length[B] { type Out = C },
res: ToInt[C]
): Int = res()
Test:
scala> doubleFunArity(math.sqrt _)
res15: Int = 1
scala> doubleFunArity(math.random _)
res16: Int = 0
scala> val g: (Double, Double) => Double = math.max _
g: (Double, Double) => Double = <function2>
scala> doubleFunArity(g)
res17: Int = 2
Note that unfortunately many math operations are overloaded, and without strong type constraint, Scala will not give you the Double version automatically, but will use the Int version for some reason:
scala> math.max _
res18: (Int, Int) => Int = <function2>
So I need the indirection math.max _: ((Double, Double) => Double) to make this work.
Not saying that this is the best way to do it in your concrete case, but I think it was a fun exploration.
Probably the easiest solution is to use overloading as
def f(g: () => Double) = 0;
def f(g: (Double) => Double) = 1;
def f(g: (Double, Double) => Double) = 2;
def f(g: (Double, Double, Double) => Double) = 2;
// ...
println(f(Math.pow _));
println(f(Math.sin _));
(You can't check function argument/return types at run time due to type erasure, so I believe you can't create a fully generic function that would satisfy your requirements.)

Scala strange implicit boxing conversion error

Can someone tell me why the following does not work?
object TestObject {
def map(f: (Double, Double) => Double, x2: Array[Double]) = {
val y = x2.zip( x2 )
val z = y.map(f)
z
}
}
Produces this error:
type mismatch; found : (Double, Double) => Double required: ((Double, Double)) => ?
In this snippet, f is a function taking two Double parameters and returning a Double.
You are attempting to call f by passing a single argument of type Tuple2[Double,Double].
You can fix this by changing the type of f in the first place:
object TestObject {
def map(f: ((Double, Double)) => Double, x2: Array[Double]) = {
val y = x2.zip( x2 )
val z = y.map(f)
z
}
}
You could also declare it as f: Tuple2[Double, Double] => Double to be clearer (this is entirely equivalent).
Conversely, you could change your call like this:
object TestObject {
def map(f: (Double, Double) => Double, x2: Array[Double]) = {
val y = x2.zip( x2 )
val z = y.map(f.tupled)
z
}
}
tupled automagically transforms your (Double, Double) => Double function into a Tuple2[Double, Double] => Double function.
Keep in mind however that the conversion will be done on each call to TestObject.map
There is a subtle difference between
f: (Double, Double) => Double // two Double arguments -> Double
and
f: ((Double, Double)) => Double // one Tuple2[Double, Double] argument -> Double
y is an Array[(Double, Double)], so it expects a method that takes a tuple and returns something, but the first f defined above doesn't match that.
You can do y.map(f.tupled) to go from the first to the second, or change the signature of f.
I think your issue is that f expects two Double arguments but you're attempting to pass it a single tuple: f((1, 2)) is different from f(1, 2).
Change the type of f to ((Double, Double) => Double) and it should work.

How does the type inferencer work on reduceLeft?

Further to my other question about reduceLeft, the signature of reduceLeft on Seq is
def reduceLeft [B >: A] (f: (B, A) ⇒ B): B
and we can call it with expressions such as
List(1,2,3,4) reduceLeft (_ + _)
In this example A is Int, so reduceLeft expects a Function2[B >: Int, Int, B]. Regardless of how reduceLeft works (which is irrelevant), how does the type inferencer know that B has a + method, when it could be of type Any?
I think the section 6.26.4 Local Type Inference of the spec sort of explains what's going on. The compiler will look for an optimal type. When the type parameter is contravariant the type chosen will be maximal (in this case Any) and otherwise (invariant or covariant) minimal (in this case Int).
There are a couple examples which I can't really relate to reduceLeft.
What I did notice is the inference seems to happen before looking at the anonymous function passed:
scala> List(1,2).reduceLeft[Any](_.toString + _)
res26: Any = 12
But If I don't help the type inferencer:
scala> List(1,2).reduceLeft(_.toString + _)
<console>:8: error: type mismatch;
found : java.lang.String
required: Int
List(1,2).reduceLeft(_.toString + _)
Edit, I'm wrong the anonymous function is taken into account, this works:
List(1,2).reduceLeft((_:Any).toString + (_:Any).toString)
There is a compiler -Ytyper-debug option that you can run on:
List(1,2).reduceLeft(_+_)
It will show you that somehow the compiler assumes the expected type of the anonymous function is (Int, Int) => Int, then it proceeds to check the _ + _ against it and succeeds and then infers B as Int. Snippet here:
typed immutable.this.List.apply[Int](1, 2).reduceLeft: [B >: Int](f: (B, Int) => B)B
adapted immutable.this.List.apply[Int](1, 2).reduceLeft: [B >: Int](f: (B, Int) => B)B to ?, undetparams=type B
typing ((x$1, x$2) => x$1.$plus(x$2)): pt = (Int, Int) => Int: undetparams=,
// some time later
typed ((x$1: Int, x$2: Int) => x$1.+(x$2)): (Int, Int) => Int
adapted ((x$1: Int, x$2: Int) => x$1.+(x$2)): (Int, Int) => Int to (Int, Int) => Int,
typed immutable.this.List.apply[Int](1, 2).reduceLeft[Int](((x$1: Int, x$2: Int) => x$1.+(x$2))): Int
I don't know why in absence of type ascription the anonymous function is assumed to be (Int, Int) => Int.
If B >: X and the compiler knows X but cannot resolve B it simply assumes B = X.
It is somewhat practical since it only has two options for B and only one is known. So absent knowing which super class it assumes that B is X. You can test the compilers decision making process with the following code.
class Y {
def bar(y:Y) = this
}
case class X( i: Int ) extends Y {
def foo(x:X)=X(i+x.i)
}
val t = new Y bar X(7)
val t2 = X(8) bar X(7)
val res = List(X(1),X(2),X(3)) reduceLeft { _ foo _ }
val res2 = List(X(1),X(2),X(3)) reduceLeft { _ bar _ } // will not compile