开发者

Scala implicit conversions between functional objects?

开发者 https://www.devze.com 2023-02-28 10:10 出处:网络
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 ta

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>
0

精彩评论

暂无评论...
验证码 换一张
取 消