Scala函数式对象之间的隐式转换?

4

我试图重新绑定scala.math中的一些函数,使它们接受和返回Float对象而不是Double对象,以便我可以将它们绑定到一个函数注册器上,该注册器适用于接受和返回Float对象的函数。我尝试了以下规则:

implicit def doubleFunc2floatFunc[T <: { def apply(x:Double):Double }] (func:T) = func(_:Float).floatValue

它不起作用。编译器抱怨我的函数是 (Double)=>Float 而不是 (Float)=>Float。有人能指点我正确的方向吗?

编辑:我在使用的代码如下:

package org.nathanmoos.magnificalc.exprtreelib.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 接受一个函数名称的 String 和一个与之关联的函数对象。


2
请展示您如何使用代码。 - Daniel C. Sobral
@Daniel C. Sobral:完成。 - Nathan Moos
Functions.register的类型签名是什么?我猜错误发生在对它的调用上,对吗? - Daniel C. Sobral
@Daniel:是的,错误发生在调用它时。Functions.register 定义如下:def register(name:String, func:(Float)=>Float) - Nathan Moos
3个回答

0

这里不需要结构类型或类型参数,

scala> implicit def doubleFunc2floatFunc(df : Double => Double) : Float => Float = (f : Float) => df(f).toFloat
doubleFunc2floatFunc: (df: (Double) => Double)(Float) => Float

然后在使用中,

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

误导性的。它实际上并不起作用——尝试使用未重载的log函数。这里似乎可以工作是因为abs有一个(Float)Float版本。 - Daniel C. Sobral

0

我不知道具体发生了什么,但它首先检查函数的返回类型,如果无法解决,则失败。但是,如果您让它有可能修复返回类型,那么它将继续检查整个函数。

因此,您可以通过创建两个隐式来实现:

implicit def doubleToFloat(d: Double): Float = d.toFloat
implicit def doubleFunc2floatFunc(df : Double => Float) : Float => Float = (f : Float) => df(f)

只是出于好奇,使用Double而不是Float会更好吗?该应用程序是一个图形计算器,该系统允许插入其他函数。 - Nathan Moos
1
@Nathan 当然。在Java领域中,“Float”是一个被遗忘的类。 - Daniel C. Sobral

0

我认为(在移除已经在predef中的隐式转换、不必要的结构类型之后,并将自己限制在没有重载的数学函数上)潜在的问题是一个弱一致性和eta扩展之间的奇怪类型推断交互。参数类型Float符合预期的参数类型Double,因此函数类型的隐式转换不会被触发;它会在结果类型上起作用,但这太迟了。它已经决定了参数类型为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>

你有任何想法为什么我的两个隐式参数一起才能使它工作?单独一个是不够的。 - Daniel C. Sobral

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接