【问题标题】:Scala: generic function multiplying Numerics of different typesScala:通用函数乘以不同类型的数字
【发布时间】:2017-04-13 02:20:38
【问题描述】:

我正在尝试编写一个通用的加权平均函数。 我想放宽对相同类型的值和权重的要求。即,我想支持说:(value:Float,weight:Int)(value:Int,weight:Float) 参数的序列,而不仅仅是:(value:Int,weight:Int)

为此,我首先需要实现一个函数,该函数接受两个通用数值并返回它们的乘积。

def times[A: Numeric, B: Numeric](x: B, y: A): (A, B) : ??? = {...}

编写签名并考虑返回类型,让我意识到我需要为 Numerics 定义某种层次结构来确定返回类型。即x:Float*y:Int=z:Floatx:Float*y:Double=z:Double

现在,Numeric 类只为相同类型的参数定义操作plustimes 等。我想我需要实现一个类型:

class NumericConverter[Numeirc[A],Numeric[B]]{
type BiggerType=???
}

这样我就可以将时间函数写为:

def times[A: Numeric, B: Numeric](x: B, y: A): (A, B) :
NumericConverter[Numeirc[A],Numeric[B]].BiggerType= {...}

并将“较小的类型”转换为“较大的类型”并将其提供给times()

我在正确的轨道上吗?我将如何“实现”BiggerType

显然我不能这样做:

type myType = if(...) Int else Float

因为它是动态评估的,所以它不能工作。

我知道我可以使用 Scalaz 等来做到这一点,但这是一个学术练习,我想了解如何编写一个基于参数类型静态返回类型的函数

如果有更简单的方法,请随时告诉我。

更新

这是我想出来的。

abstract class NumericsConvert[A: Numeric,B: Numeric]{

    def AisBiggerThanB: Boolean

    def timesA=new PartialFunction[(A,B), A] {
        override def isDefinedAt(x: (A, B)): Boolean = AisBiggerThanB
        override def apply(x: (A, B)): A = implicitly[Numeric[A]].times(x._1, x._2.asInstanceOf[A])
    }

    def timesB=new PartialFunction[(A,B), B] {
        override def isDefinedAt(x: (A, B)): Boolean = !AisBiggerThanB
        override def apply(x: (A, B)): B = implicitly[Numeric[B]].times(x._1.asInstanceOf[B], x._2)
    }
    def times: PartialFunction[(A, B), Any] = timesA orElse timesB
}

def times[A: Numeric, B: Numeric](x: B, y: A)= implicitly[NumericsConvert[A,B]].times(x,y)

这很愚蠢,因为我必须为两者创建隐含

IntDouble extends NumericsConvert[Int,Double]

DoubleInt extends NumericsConvert[Double,Int]

更不用说times 的返回类型现在是Any,但无论如何,我的时间函数出现错误。我想我会在这里添加它,以防它可能有助于找到解决方案。所以附带的问题:我如何将一个类/函数的上下文绑定类型传递给另一个,就像我尝试做的那样

【问题讨论】:

    标签: scala generics numeric implicit


    【解决方案1】:

    我认为你让这件事变得比需要的更难。

    您需要“证据”证明两个参数都是Numeric。有了这一点,让证据发挥作用。 Scala 将使用numeric widening,因此结果是两种接收类型中更通用的。

    def mult[T](a: T, b: T)(implicit ev:Numeric[T]): T =
      ev.times(a,b)
    

    如果你想变得更漂亮,你可以引入所需的隐式。然后它更容易阅读和理解。

    def mult[T: Numeric](a: T, b: T): T = {
      import Numeric.Implicits._
      a * b
    }
    

    证明:

    mult(2.3f , 7)  //res0: Float = 16.1
    mult(8, 2.1)    //res1: Double = 16.8
    mult(3, 2)      //res2: Int = 6
    

    有关泛型类型和数值扩展的更多信息,this question 及其答案值得研究。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-11-17
    • 2016-06-24
    • 2015-12-28
    • 2014-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多