Scala “编写隐式派生”;“法律”;

Scala “编写隐式派生”;“法律”;,scala,implicit-conversion,implicit,Scala,Implicit Conversion,Implicit,我试图设计一个玩具CoversionRate实现,以了解如何通过链式隐式定义对“定律”进行编码。编译以下代码: case-class-ConversionRate[XImplicit无法从您的规则中派生任何可能的类型,因为它很容易在您有无限可能的情况下结束: id[X]: X => X x: A => B y: B => C 可以组成 z = x andThen y 但也许它可以用 z = x andThen id[B] andThen y // or z = id[A]

我试图设计一个玩具
CoversionRate
实现,以了解如何通过链式隐式定义对“定律”进行编码。编译以下代码:


case-class-ConversionRate[XImplicit无法从您的规则中派生任何可能的类型,因为它很容易在您有无限可能的情况下结束:

id[X]: X => X
x: A => B
y: B => C
可以组成

z = x andThen y
但也许它可以用

z = x andThen id[B] andThen y // or
z = id[A] andThen x andThen y // or
z = x andThen y andThen id[C] // or
z = id[A] andThen x andThen y andThen id[C] //
...
你看到了吗

同时,派生应该是明确的,当你从你的“原语”隐式开始,并试图将它们组合成你的“目标”隐式时,应该只有一种可能的方法。当Scala发现有一些歧义时,它停止派生

在您的示例中,您使用
ConversionRate[Y,USD]
ConversionRate[Y,USD]
组合成
ConversionRate[X,Y]
。但这并不妨碍您执行以下操作:

ConversionRate[USD, USD] combine with
ConversionRate[USD, USD] combine with
ConversionRate[USD, USD] combine with...
这样做的一种方法是,定义转换的方式应确保只有一种转换方式,即您不能轻易中断转换,例如:

case class USDConversionRate[A <: Currency](rate: Double)
// implicit conversion rates

case class ConversionRate[X <: Currency, Y <: Currency](rate: Double) extends AnyVal
object ConversionRate {
  implicit def combine[X <: Currency, Y <: Currency](
    implicit
    ev1: X =:!= USD.type, // available in shapeless
    ev2: Y =:!= USD.type, // proves type inequality
    ev3: X =:!= Y,        // which we use to force only one way to derive each pair
    xFromUSD: USDConversionRate[X],
    yFromUSD: USDConversionRate[Y],
  ): ConversionRate[X, Y] = ...

  implicit def toUSD[X <: Currency](
    implicit X =:!= USD.type,
    xFromUSD: USDConversionRate[X]
  ): ConversionRate[X, USD.type] = ...

  implicit def fromUSD[X <: Currency](
    implicit X =:!= USD.type,
    xFromUSD: USDConversionRate[X]
  ): ConversionRate[USD.type, X] = ...

  implicit def unit: ConversionRate[X, X] = ...
}

case class USDConversionRate[A在仔细研究之后,我认为我找到了一个更简单的解决方案,使用低优先级隐式而不是无形状运算符来打破隐式循环


case-class-ConversionRate[X谢谢!我知道如何打破歧义,但我不知道
=:!=
是可用的。您的回答让我走上了正确的道路。我再次阅读了隐式解析的相关内容,使用低优先级隐式可以在不使用shapeless的情况下实现同样的效果。
case class USDConversionRate[A <: Currency](rate: Double)
// implicit conversion rates

case class ConversionRate[X <: Currency, Y <: Currency](rate: Double) extends AnyVal
object ConversionRate {
  implicit def combine[X <: Currency, Y <: Currency](
    implicit
    ev1: X =:!= USD.type, // available in shapeless
    ev2: Y =:!= USD.type, // proves type inequality
    ev3: X =:!= Y,        // which we use to force only one way to derive each pair
    xFromUSD: USDConversionRate[X],
    yFromUSD: USDConversionRate[Y],
  ): ConversionRate[X, Y] = ...

  implicit def toUSD[X <: Currency](
    implicit X =:!= USD.type,
    xFromUSD: USDConversionRate[X]
  ): ConversionRate[X, USD.type] = ...

  implicit def fromUSD[X <: Currency](
    implicit X =:!= USD.type,
    xFromUSD: USDConversionRate[X]
  ): ConversionRate[USD.type, X] = ...

  implicit def unit: ConversionRate[X, X] = ...
}