代码之家  ›  专栏  ›  技术社区  ›  waterlooalex

scala:在泛型类中进行数值运算的最佳方法是什么?

  •  7
  • waterlooalex  · 技术社区  · 15 年前

    在scala中,我希望能够编写使用诸如>、/、*等运算符的泛型类,但我不知道如何约束它,使它能够工作。

    我研究了用有序的[t]来约束t,但这似乎不起作用,因为只有richxxx(例如richint)扩展它,而不是in t等。我还看到numeric[t],这是否仅在scala 2.8中可用?

    下面是一个具体的例子:

    class MaxOfList[T](list: List[T] ) {
      def max = {
        val seed: Option[T] = None
    
        list
          .map( t => Some(t))
          // Get the max      
          .foldLeft(seed)((i,m) => getMax(i,m) )
      }
    
      private def getMax(x: Option[T], y: Option[T]) = {
        if ( x.isDefined && y.isDefined )
          if ( x > y ) x else y
        else if ( x.isDefined )
          x
        else
          y
      }
    }
    

    此类无法编译,因为有许多TS不支持>等。

    思想?

    目前,我已经使用了混合特性来解决这个问题:

    /** Defines a trait that can get the max of two generic values
     */
    trait MaxFunction[T] {
      def getMax(x:T, y:T): T
    }
    
    /** An implementation of MaxFunction for Int
     */
    trait IntMaxFunction extends MaxFunction[Int] {
      def getMax(x: Int, y: Int) = x.max(y)
    } 
    
    /** An implementation of MaxFunction for Double
     */
    trait DoubleMaxFunction extends MaxFunction[Double] {
      def getMax(x: Double, y: Double) = x.max(y)
    } 
    

    如果我们更改了原始类,就可以在实例化时将其混合在一起。

    P.S.Mitch,灵感来自于你对GetMax的重写,这里是另一个:

      private def getMax(xOption: Option[T], yOption: Option[T]): Option[T] = (xOption,yOption) match {
        case (Some(x),Some(y)) => if ( x > y ) xOption else yOption
        case (Some(x), _) => xOption
        case _ => yOption
      }
    
    3 回复  |  直到 10 年前
        1
  •  9
  •   Mitch Blevins    15 年前

    你可以使用 View Bounds .

    简而言之, def foo[T <% U](t: T) 是一个函数,它将采用任何已隐式转换为U或可以隐式转换为U的T。由于int可以转换为richint(包含所需方法),这是一个很好的用法示例。

    class MaxOfList[T <% Ordered[T]](list: List[T] ) {
      def max = {
        val seed: Option[T] = None
        list.foldLeft(seed)(getMax(_,_))
      }
    
      private def getMax(xOption: Option[T], y: T) = (xOption, y) match {
        case (Some(x), y) if ( x > y ) => xOption
        case (_, y) => Some(y)
      }
    }
    

    ps-i重写了getmax(…)方法以比较值而不是选项本身,并使用模式匹配而不是定义(…)

    pps-scala 2.8将具有可能使用的数字特性。 http://article.gmane.org/gmane.comp.lang.scala/16608


    补遗

    对于咯咯笑,这里有一个超级紧凑的版本,它完全消除了getmax方法:

    class MaxOfList[T <% Ordered[T]](list: List[T] ) {
      def max = list.foldLeft(None: Option[T]) {
          case (Some(x), y) if ( x > y ) => Some(x)
          case (_, y) => Some(y)
      }
    }
    

    又一个附录

    对于大型列表,此版本会更高效…避免为每个元素创建一些(x):

    class MaxOfList[T <% Ordered[T]](list: List[T] ) {
      def max = {
        if (list.isEmpty) None
        else Some(list.reduceLeft((a,b) => if (a > b) a else b))
      }
    }
    

    最后一个,我保证!

    此时,您可以放弃类并使用函数:

      def max[T <% Ordered[T]](i: Iterable[T]) = {
        if (i.isEmpty) None
        else Some(i.reduceLeft((a,b) => if (a > b) a else b))
      }
    
        2
  •  2
  •   rightfold Eugene Lazutkin    10 年前

    Numeric[T] 在Scala 2.8中,

    scala> case class MaxOfList[T : Numeric](list: List[T]) {
         |     def max = if(list.isEmpty) None else Some(list.max)
         | }
    defined class MaxOfList
    
    scala> MaxOfList(1::2::3::9::7::Nil).max
    
    res1: Option[Int] = Some(9)
    
    scala> MaxOfList(1.5::3.9::9.2::4.5::Nil).max
    
    res2: Option[Double] = Some(9.2)
    
    scala> MaxOfList(Nil: List[Byte]).max
    
    res3: Option[Byte] = None
    
    scala>
    
        3
  •  1
  •   Community Nick Dandoulakis    7 年前

    回答如下 Mitch Blevins 就是这样 视界 是为了现在,虽然 Numeric 只是在scala 2.8中添加了一些内容,而不是它不依赖于任何scala 2.8功能。我们可以在scala 2.7上做同样的事情。

    您可能对我为之编写的一些通用代码片段感兴趣 Rosetta Code :