Scala:在隐式参数中抽象依赖于路径的类型

上海

假设我有一堂课:

abstract class NumericCombine[A:Numeric,B:Numeric]{
        type AB <: AnyVal
    }

我想定义一个返回 type 值的函数NumericCombine[A,B].AB例如:

def plus[A: Numeric,B:Numeric](x: A, y: B): NumericCombine[A,B].AB

但是编译器不允许我.AB在 plus 中引用

仅供参考,是这个问题的背景。

我想提供:

implicit object IntFloat extends NumericCombine[Int,Float]{override type AB = Float}
implicit object FloatInt extends NumericCombine[Float,Int]{override type AB = Float}

和它的其他 44 个朋友(7 * 6-2),以便我可以定义我plus的如下:

def plus[A: Numeric,B:Numeric](x: A, y: B): NumericCombine[A,B].AB =
{
type AB = Numeric[NumericCombine[A,B].AB]
implicitly[AB].plus(x.asInstanceOf[AB],y.asInstanceOf[AB])
}

plus(1f,2)//=3f
plus(1,2f)//=3f

我知道 Scala 中的值转换允许我定义

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

并实现上文建议的行为在这里,但因为我想用这个功能作为一个更大的功能(这是在为这个问题的背景下提到的链接描述)的一部分,我需要两到参数化功能AB

更新:

我在这方面取得了一些不错的进展。

NumericCombine现在看起来像这样:

abstract class NumericCombine[A: Numeric, B: Numeric] {
        type AB <: AnyVal

        def fromA(x: A): AB
        def fromB(y: B): AB

        val numeric: Numeric[AB]

        def plus(x: A, y: B): AB = numeric.plus(fromA(x), fromB(y))
        def minus(x: A, y: B): AB = numeric.minus(fromA(x), fromB(y))
        def times(x: A, y: B): AB = numeric.times(fromA(x), fromB(y))
    }

我的加号功能看起来像:

def plus[A: Numeric, B: Numeric](x: A, y: B)(implicit ev:NumericCombine[A,B])
        : ev.AB = ev.plus(x, y)

需要的加权平均函数plus最终变得有点复杂:

def accumulateWeightedValue[A: Numeric,B: Numeric]
            (accum: (A, NumericCombine[A, B]#AB), ValueWithWeight: (A, B))
            (implicit combine: NumericCombine[A, B], timesNumeric: Numeric[NumericCombine[A, B]#AB])
            :(A,NumericCombine[A, B]#AB)=

这是一个接受(A,AB),(A,B)并返回的函数(A,AB)我在内部使用它,weightedSum它只是聚合了这个:

def weightedSum[A: Numeric,B: Numeric](weightedValues: GenTraversable[(A, B)])
(implicit numericCombine: NumericCombine[A, B], plusNumeric: Numeric[NumericCombine[A, B]#AB])
: (A, NumericCombine[A, B]#AB)

现在,这编译得很好。第二个隐式参数似乎确实有问题。即 Numeric[AB] 当我使用隐式值运行它时说NumericCombine[Int,Float]存在。它给了我:

找不到参数 plusNumeric 的隐式值:Numeric[NumericCombine[Int,Float]#AB]

请注意,在 NumericCombine 中,我有一个 Numeric[AB],它应该可用于隐式查找。在以下情况下将其存储在本地[Int,Float]

val lst: Seq[(Int, Float)] =List((1,3f),(1,4f))
implicit val num: Numeric[Float] = IntFloat.numeric //IntFloat extends NumericCombine[Int,Float]
weightedSum(lst)

在调用需要它的函数之前在局部变量中似乎没有任何影响。那么为什么它会被隐式系统拾取。

PH88

* 2017 年 4 月 18 日:根据作者的最新代码进行更新 *

* 2017 年 4 月 19 日 *

  • 添加NumericCombine#Implicits以备不时之需
  • 删除AnyVal约束以支持任何Numeric类型,例如BigInt
  • 重构 NumericCombine

你需要辅助模式

import scala.collection.GenSeq

trait NumericCombine[A, B] {
  type AB

  def fromA(x: A): AB

  def fromB(y: B): AB

  val numericA: Numeric[A]
  val numericB: Numeric[B]
  val numericAB: Numeric[AB]

  // For convenience, caller can 'import combine.Implicits._'
  // to bring the Numeric's into the current scope
  object Implicits {
    implicit def implicitNumericA = numericA

    implicit def implicitNumericB = numericB

    implicit def implicitNumericAB = numericAB
  }

  def plus(x: A, y: B): AB = numericAB.plus(fromA(x), fromB(y))

  def minus(x: A, y: B): AB = numericAB.minus(fromA(x), fromB(y))

  def times(x: A, y: B): AB = numericAB.times(fromA(x), fromB(y))
}

object NumericCombine {
  type Aux[A, B, _AB] = NumericCombine[A, B] {
    type AB = _AB
  }

  private def combine[A, B, _AB](fa: A => _AB, fb: B => _AB)
                               (implicit
                                _numericA: Numeric[A],
                                _numericB: Numeric[B],
                                _numericAB: Numeric[_AB]
                               ): NumericCombine[A, B] = new NumericCombine[A, B] {
      override type AB = _AB

      override def fromA(x: A): AB = fa(x)

      override def fromB(y: B): AB = fb(y)

      override val numericA: Numeric[A] = _numericA
      override val numericB: Numeric[B] = _numericB
      override val numericAB: Numeric[AB] = _numericAB
    }

  implicit lazy val IntFloat  = combine[Int, Float, Float](_.toFloat, identity)
  implicit lazy val BigIntBigDecimal  = combine[BigInt, BigDecimal, BigDecimal](i => BigDecimal(i), identity)

}

implicit class ValuesWithWeight[A, B](val weightedValue: (A, B)) {
  def weight: A = weightedValue._1

  def value: B = weightedValue._2
}

def weightedSum[A, B, AB]
(valuesWithWeight: GenSeq[(A, B)])
(implicit combine: NumericCombine.Aux[A, B, AB]):
(A, AB) = {

  import combine.Implicits._

  val z: (A, AB) =
    (combine.numericA.zero, combine.numericAB.zero)

  def accumulateWeightedValue(accum: (A, AB), valueWithWeight: (A, B)): (A, AB) = {
    val weightedValue = combine.times(valueWithWeight.weight, valueWithWeight.value)
    (
      combine.numericA.plus(accum.weight, valueWithWeight.weight),
      combine.numericAB.plus(accum.value, weightedValue)
    )
  }

  valuesWithWeight.aggregate(z)(
    accumulateWeightedValue,
    // dataOps.tuple2.plus[A,AB]
    {
      case ((a1, ab1), (a2, ab2)) =>
        (combine.numericA.plus(a1, a2) ->
          combine.numericAB.plus(ab1, ab2))
    }
  )
}

weightedSum(Seq(1 -> 1.5f, 2 -> 1f, 3 -> 1.7f))
weightedSum(Seq(BigInt(1) -> BigDecimal("1.5"), BigInt(2) -> BigDecimal("1"), BigInt(3) -> BigDecimal("1.7")))

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

Scala类型投影:在依赖于路径的特征中拾取对象

从依赖于路径的类型混合中访问值

Scala中依赖类型的隐式解析

如何在Scala中将依赖于路径的类型与类型类一起使用

Scala-抽象类型和隐式参数解析

正确指定依赖于路径的类型注释

CompileTimeError: 部分实例化中的类型参数必须被实例化,因此不允许依赖于类型参数

不允许依赖于Julia中类型定义中整数类型参数的表达式

“特殊方法的隐式使用始终依赖于特殊方法的类级绑定”

当类依赖于隐式时,是否有惯用的方法将类转换为对象?

关于路径依赖类型的上下文边界和隐式参数列表的行为

如何为依赖于Rust中泛型类型参数的结构的关联函数定义不同的实现?

使用'type'关键字和依赖于路径的类型覆盖类型

Scala隐式参数的类型查找失败

Scala嵌套隐式类型参数

如果仅依赖于其自身的模板参数,该函数类型是否依赖?

处理依赖于参数的动态请求

类型别名如何使用来指定依赖于模板参数的模板模板参数?

依赖于泛型参数作为函数的值参数的类型

Scala中的隐式抽象类构造函数参数和继承

如何让Typescript知道依赖于传入参数的函数的返回类型

打字稿有没有办法推断依赖于输入参数的类型?

C#泛型-返回类型依赖于参数的列表。

为什么关联常量不依赖于类型参数?

如何定义依赖于参数包转换的函数的返回类型?

在依赖于模板类型的模板化函数参数中期望嵌套属性

如何使参数的默认值依赖于另一个参数(在Python中)?

Scala 中的隐式函数类型

从依赖于交互式地图的表中收集数据