val divide = (num: Double, den: Double) => {
num / den
}
//type of pafv1 is () => (Double,Double) => Double
val pafv1 = divide _
//type of pafv2 is Double => Double
val pafv2 = divide(_:Double,2)
Why type of pafv1 is not (Double,Double) => Double?
When divide is a simple method, type of pafv1 is (Double,Double) => Double.
I think the explanation comes from eta expansion.
Scala makes getters and setters of vals, which means divide is in fact a method def divide = (num: Double, den: Double) => { num / den }
When you do val pafv1 = divide _, this expands it into the eta expanded version of divide, namely () => (num: Double, den: Double) => { num / den }
Why is it doing eta expansion? Because you are trying to use a method as a value (you are partially evaluating _, forcing the result to be a function value).
That's weird... If you compile this piece of code:
class C {
val f = (n: Double, d: Double) => n / d
val pf = f _
}
with the -print flag, the desugared code is:
package <empty> {
class C extends Object {
private[this] val f: Function2 = _;
<stable> <accessor> def f(): Function2 = C.this.f;
private[this] val pf: Function0 = _;
<stable> <accessor> def pf(): Function0 = C.this.pf;
final <artifact> private[this] def $anonfun$f$1(n: Double, d: Double): Double = n./(d);
final <artifact> private[this] def $anonfun$pf$1(): Function2 = C.this.f();
def <init>(): C = {
C.super.<init>();
C.this.f = {
((n: Double, d: Double) => C.this.$anonfun$f$1(n, d))
};
C.this.pf = {
(() => C.this.$anonfun$pf$1())
};
()
}
}
}
Some observations:
The val f declaration is split into a private this val f: Function2 and into an <stable> <accessor> def f(): Function2.
The stable accessor method is wrapped into an anonymous function $anonfun$pf$1() that simply redirects all calls to C.this.f().
The pf eta-expands the parameterless $anonfun$pf$1() method into a function that takes no arguments and returns a Function2.
If I had to write down an equivalent piece of code that demonstrates "what actually happens", I'd probably write something like this:
class C2 {
var f: Function2[Double, Double, Double] = _
def fAccessor(): Function2[Double, Double, Double] = this.f
f = (n: Double, d: Double) => n / d
val pf = fAccessor _
}
Here you see that:
fAccessor is a method without arguments that returns a Function2
pf is eta-expansion of the accessor method fAccessor, which also takes zero arguments, and returns a Function2.
So, to conclude: for some weird reason, f _ is the eta-expansion of the otherwise invisible accessor method. I think this should not compile at all, looks like an abstraction leak (some synthetic implementation dependent method symbols appearing out of nowhere).
What you might have wanted:
val pf: Double => Double => Double = n => f(n, _)
I usually "wrap" the function in a case expression:
val divide = (num: Double, den: Double) => num / den
val partialDivide: PartialFunction[(Double, Double), Double] = {
case (num: Double, den: Double) if den != 0 => divide(num, den)
}
partialDivide(4, 2)
partialDivide(4, 0) // throws a `MatchError`
You can play around with this code on Scastie.
You can find a very thorough explanation of the topic here.
From the scala language specification one can read:
If e is a parameterless method … , e _ represents the function of type () => T, which evaluates e when it is applied to the empty parameterlist ().
This is what we see happening.
Related
I have the following code
object Test {
def bar: String => Double = {
foo[String](_.toDouble)
}
def baz: (Double, Double) => Double = {
foo[(Double, Double)] {
case (d1, d2) => d1 + d2
}
}
def foo[T](f: T => Double): T => Double = {
f
}
}
bar works with no trouble, as expected. I am trying to get a similar thing working with mutli parameter function as one of the inputs, but this doesn't work, because scala sees the foo[(Double, Double)] as a tuple type rather than as a function parameter. Is there any way to tell scala this is a function parameter, rather than a tuple?
the code: https://scastie.scala-lang.org/sCYyU6ziT3mKOhkBiofAaQ
I think the reason this didn't work for you is that you don't access the two separate arguments to the baz method, which need to be packaged into a tuple before calling foo. (I think there's some discussion about being able to convert parameter lists to/from tuples, but that's not currently possible.) Try this definition instead:
object Test {
def bar: String => Double = {
foo[String](_.toDouble)
}
def baz: (Double, Double) => Double = {(p1, p2) =>
foo[(Double, Double)] {
case(d1, d2) => d1 + d2
}((p1, p2))
}
def foo[T](f: T => Double): T => Double = f
}
If I understand your intent correctly, this would be used like this (in the Scala REPL):
scala> Test.bar("5.0")
val res0: Double = 5.0
scala> Test.baz(3.0, 5.0)
val res1: Double = 8.0
However, this seems a little muddled. If bar and baz store method references, then they should be declared val, instead of def:
object Test {
val bar: String => Double = {
foo[String](_.toDouble)
}
val baz: (Double, Double) => Double = {(p1, p2) =>
foo[(Double, Double)] {
case(d1, d2) => d1 + d2
}((p1, p2))
}
def foo[T](f: T => Double): T => Double = f
}
Which has the same usage syntax and produces the same output:
scala> Test.bar("5.0")
val res2: Double = 5.0
scala> Test.baz(3.0, 5.0)
val res3: Double = 8.0
But even that is still fairly clumsy. bar is a reference to a function that takes a String and returns a Double, while baz is a reference to a function that takes two Doubles and returns a Double. So why not just make bar and baz methods in their own right, instead of method references? This would produce:
object Test {
def bar(s: String): Double = foo[String](_.toDouble)(s)
def baz(p1: Double, p2: Double): Double = {
foo[(Double, Double)] {
case(d1, d2) => d1 + d2
}((p1, p2))
}
def foo[T](f: T => Double): T => Double = f
}
which again is used in the same way:
scala> Test.bar("5.0")
val res4: Double = 5.0
scala> Test.baz(3.0, 5.0)
val res5: Double = 8.0
And, of course, foo itself is redundant, since it is identical to its argument. So this could all be written far more simply as just:
object Test {
def bar(s: String): Double = s.toDouble
def baz(p1: Double, p2: Double): Double = p1 + p2
}
trouble-shooting env: sbt console (Scala 2.11.8) & spark-shell (Spark 2.3, Scala 2.11)
I have a higher-order function with a view bound type T... but that arg t: T type signature turns from T <% Double to Nothing when the function is partially applied.
Toy example to demonstrate:
// tot: T needs to work on (at least) Int, Long, Double, Float
// no common supertype -> some kind of context bound
def func[T <% Double](isValid: Boolean)(tot: T, cnt: Int): Double =
if (isValid) tot.toDouble / cnt else Double.NaN
When I try to partially apply isValid, I'd expect the result to be type (T, Int) => Double but instead the type ends up (Nothing, Int) => Double, and I cannot pass in arg tot.
val f1 = func(true)_ // f1: (Nothing, Int) => Double = <function2>
val f2 = func(false)_ // f2: (Nothing, Int) => Double = <function2>
val g1 = f1(10.0, 1)
// <console>:40: error: type mismatch;
// found : Double(10.0)
// required: Nothing
// val g1 = f1(10.0, 1)
I'm not getting any error messages when defining f1 or f2... so it's hard to interpret. It just converts arg tot: T to type Nothing.
Checking scala doc... I see scala.Nothing is a subtype of EVERY other type, so I thought maybe it was losing the view bound on T... which was maybe related to type erasure... so I tried using ClassTag...
import scala.reflect.ClassTag
def func[T <% Double](isValid: Boolean)(tot: T, cnt: Int)(implicit tag: ClassTag[T]): Double =
if (isValid) tot.toDouble / cnt else Double.NaN
That doesn't help. Same problem.
if I try using implicit num: Numeric[T] it chokes on type Nothing in a new way...
def func[T](isValid: Boolean)(tot: T, cnt: Int)( implicit num: Numeric[T] ): Double =
if (isValid) num.toDouble(tot) / cnt else Double.NaN
val f1 = func(true)_
// <console>:40: error: could not find implicit value for parameter num: Numeric[Nothing]
// val f1 = func(true)_
If I apply it all at once (using first 'func' at top), it works fine...
val g1 = func(true)(10.0, 1)
// g1: Double = 10.0
But in my real (non-toy) code, that's not an option.
What is happening here, and how can I make func work when partially applied?
EDIT [#Alexey's solution]
I can't get the preferred 'def' approach to work.
def func[T <% Double](isValid: Boolean)(tot: T, cnt: Int): Double =
if (isValid) tot.toDouble / cnt else Double.NaN
// func: [T](isValid: Boolean)(tot: T, cnt: Int)(implicit evidence$1: T => Double)Double
def f1[T <% Double]: ((T, Int) => Double) = func[T](true)_
// f1: [T](implicit evidence$1: T => Double)(T, Int) => Double
f1[Double](10.0, 1)
<console>:41: error: too many arguments for method f1: (implicit evidence$1: Double => Double)(Double, Int) => Double
f1[Double](10.0, 1)
When I try to partially apply isValid, I'd expect the result to be type (T, Int) => Double
Values can't be generic. So it can have this type for some specific T, but you don't provide exactly the parameters which would allow inferring it. You can specify e.g.
val f1 = func[TheTypeYouWant](true) _
or
val f1: (TheTypeYouWant, Int) => Double = func(true) _
If you want it to be generic, it has to be a def again:
def f1[T <% Double] = func[T](true) _
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
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.)
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.