Scala implicit conversions between functional objects?
I am trying to re-bind some of the functions in scala.math
to take and return Float
objects rather than Double
objects so that I can bind them to a function registrar that works with functions that take and return Float
objects. I've tried this rule:
implicit def doubleFunc2floatFunc[T <: { def apply(x:Double):Double }] (func:T) = func(_:Float).floatValue
and it doesn't work. The compiler complains that my functions are (Double)=>Float
rather than (Float)=>Float
. Can anyone point me in the right direction?
EDIT: the code I am using this in is as follows:
package org.nathanmoos.magnificalc.ex开发者_开发百科prtreelib.functions
import org.nathanmoos.magnificalc.exprtreelib.Functions
import scala.math._
object InternalFunctions
{
implicit def float2double(x:Float) = x.doubleValue
// need an implicit def doubleFunc2floatFunc
implicit def double2float(x:Double) = x.floatValue
def csc(x:Float):Float = 1f/sin(x)
def sec(x:Float):Float = 1f/cos(x)
def cot(x:Float):Float = 1f/tan(x)
def registerAll() = {
Functions.register("ln", log _)
Functions.register("log", log10 _)
Functions.register("sqrt", sqrt _)
Functions.register("sin", sin _)
Functions.register("cos", cos _)
Functions.register("tan", tan _)
Functions.register("csc", csc _)
Functions.register("sec", sec _)
Functions.register("cot", cot _)
Functions.register("sinh", sinh _)
Functions.register("cosh", cosh _)
Functions.register("tanh", tanh _)
Functions.register("acos", acos _)
Functions.register("asin", asin _)
Functions.register("atan", atan _)
}
}
Functions.register
takes a String
for the function's name and a function-object to associate it with.
I don't know what exactly is going on, but it first checks for the return type of the function, and then fails if it can't solve that. But if you do make it possible for it to fix the return type, then it proceeds to check the whole function.
So you can do it by creating two implicits:
implicit def doubleToFloat(d: Double): Float = d.toFloat
implicit def doubleFunc2floatFunc(df : Double => Float) : Float => Float = (f : Float) => df(f)
There's no need for structural types or type parameters here,
scala> implicit def doubleFunc2floatFunc(df : Double => Double) : Float => Float = (f : Float) => df(f).toFloat
doubleFunc2floatFunc: (df: (Double) => Double)(Float) => Float
Then in use,
scala> val f : Float => Float = scala.math.abs
f: (Float) => Float = <function1>
scala> f(-1.0)
<console>:8: error: type mismatch;
found : Double(-1.0)
required: Float
f(-1.0)
^
scala> f(-1.0f)
res1: Float = 1.0
I think the underlying issue (after we remove implicits which are already in predef, unnecessary structural types, and then limit ourselves to math functions which aren't overloaded) is a weird type inference interaction between weak conformance and eta expansion. The parameter type Float conforms to the expected parameter type Double, and so the implicit conversion for the function type doesn't trigger; it kicks in for the result type, which is too late. It has already decided the parameter type is Double.
scala> implicit def dd2ff(x: Double => Double): Float => Float = x => x
dd2ff: (x: (Double) => Double)(Float) => Float
scala> def dd(x: Double) = x
dd: (x: Double)Double
scala> val ff: Float => Float = (dd _)
<console>:9: error: type mismatch;
found : Double
required: Float
val ff: Float => Float = (dd _)
^
scala> val x = dd _
x: (Double) => Double = <function1>
scala> val ff: Float => Float = x
ff: (Float) => Float = <function1>
精彩评论