Scala:基于同一层次结构的另一类型参数值限制参数

Scala:基于同一层次结构的另一类型参数值限制参数,scala,types,type-bounds,Scala,Types,Type Bounds,这个问题可能有点令人困惑,但其目的是: 我想将一个值限制为paremeter类型层次结构中的另一个值。考虑到它们都是类型,如果能强制执行类似的代码就好了 sealed trait Direction case object Buy extends Direction case object Sell extends Direction case class Trade[D <: Direction](id: Long, itemId: Long, quantity: Int

这个问题可能有点令人困惑,但其目的是:

我想将一个值限制为paremeter类型层次结构中的另一个值。考虑到它们都是类型,如果能强制执行类似的代码就好了

sealed trait Direction
case object Buy     extends Direction
case object Sell    extends Direction

case class Trade[D <: Direction](id: Long, itemId: Long, quantity: Int)

case class Hedge[D <: Direction, ??? -> O is D's OppositeDirection](id: Long, itemId: Long, openingTrade: Trade[D], closingTrade: Trade[O])  
是有效的,但不应允许我为不正确的配对创建对冲。e、 g:

val invalidHedge = Hedge[Buy, Sell](id = 563, itemId = 10, openingTrade= trade1, closingTrade = trade1)
如有任何建议,将不胜感激

更新:

如果在任何时候我希望我能接受不止一个答案,那就是这一次。所有答案均有效且质量良好。我将选择最能解决问题和产生可读性最强错误的一个。选择的答案有相反的值可供使用(这肯定会派上用场),并且不需要隐含。它还生成一条最清晰的错误消息。类型不等式非常优雅,但是其中有一些神奇的元素,特别是它需要两个消歧。从代码中删除它会停止工作,没有明显的原因。隐式对当然是一个很好的解决方案,它与原始问题非常相似,但没有对立面那么有用,也没有对立面那么自由

感谢大家的精彩回答和快速回复

为了完成,以下是所有重新加工的代码:

object NotEquality {
  trait =!=[A, B]

  implicit def neq[A, B] : A =!= B = null
  implicit def neqAmbig1[A] : A =!= A = null
  implicit def neqAmbig2[A] : A =!= A = null //Without this duplicated line, the compiler will ignore the restriction and silently fail. Why?
}

object Trades {
  sealed trait Direction
  case object Buy     extends Direction
  case object Sell    extends Direction

  import NotEquality._
  case class Trade[D <: Direction](id: Long, itemId: Long, quantity: Int)
  case class Hedge[D <: Direction, O <: Direction](id: Long, itemId: Long, openingTrade: Trade[D], closingTrade: Trade[O])(implicit ev: D =!= O)
}


object TradesNeq extends App {
  import NotEquality._
  import Trades._

  val trade1 = Trade[Buy.type](1,10,100)
  val trade2 = Trade[Sell.type](2,10,-100)

  val validHedge = Hedge[Buy.type, Sell.type](id = 563, itemId = 10, openingTrade= trade1, closingTrade = trade2)

  println(s"Valid Hedge: ${validHedge}")
//  val invalidHedge = Hedge[Buy.type, Buy.type](563,10,trade1,trade1)
//  println(s"InvalidHedge ${invalidHedge}")
}


object TradesDOImpl extends App {
  sealed trait Direction
  case object Buy     extends Direction
  case object Sell    extends Direction

  class TradeDirection[D <: Direction, Op <: Direction]

  implicit val BuyToSell = new TradeDirection[Buy.type, Sell.type]
  implicit val SellToBuy = new TradeDirection[Sell.type, Buy.type]

  case class Trade[D <: Direction](id: Long, itemId: Long, quantity: Int)

  case class Hedge[D <: Direction, O <: Direction](id: Long, itemId: Long, openingTrade: Trade[D], closingTrade: Trade[O])(implicit d: TradeDirection[D, O])

  val trade1 = Trade[Buy.type](id = 1, itemId = 10, quantity = 100)
  val trade2 = Trade[Sell.type](id = 2, itemId = 10, quantity = -100)

  val validHedge = Hedge[Buy.type, Sell.type](id = 563, itemId = 10, openingTrade= trade1, closingTrade = trade2)
  println(s"Valid Hedge: ${validHedge}")
  val invalidHedge = Hedge[Buy.type, Buy.type](563,10,trade1,trade1)
  println(s"InvalidHedge ${invalidHedge}")
}


object TradesOpposite extends App {
    sealed trait Direction
    abstract class OppositeDirection[D <: Direction](val opposite: D) extends Direction
    abstract class Buy(opposite: Sell) extends OppositeDirection[Sell](opposite)
    case object Buy extends Buy(Sell)
    abstract class Sell(opposite: Buy) extends OppositeDirection[Buy](opposite)
    case object Sell extends Sell(Buy)

    case class Trade[D <: Direction](id: Long, itemId: Long, quantity: Int)

    case class Hedge[D <: Direction, O <: OppositeDirection[D]](id: Long, itemId: Long, openingTrade: Trade[D], closingTrade: Trade[O])

    val trade1 = Trade[Buy](id = 1, itemId = 10, quantity = 100)
    val trade2 = Trade[Sell](id = 2, itemId = 10, quantity = -100)

    val validHedge = Hedge[Buy, Sell](id = 563, itemId = 10, openingTrade= trade1, closingTrade = trade2)
    println(s"Valid Hedge: ${validHedge}")
//    val invalidHedge = Hedge[Buy, Buy](563,10,trade1,trade1)
//    println(s"InvalidHedge ${invalidHedge}")

}
对象质量{
特质=!=[A,B]
隐式def neq[A,B]:A=!=B=null
隐式定义neqAmbig1[A]:A=!=A=null
隐式def neqAmbig2[A]:A=!=A=null//如果没有此重复行,编译器将忽略该限制并以静默方式失败。为什么?
}
实物交易{
封闭性状方向
case对象扩展方向
case对象扩展方向
进口质量_

案例类交易[D您可以将每个
方向
对象的类型参数化为其相反的
方向

trait OppositeDirection[D <: Direction] extends Direction
trait Buy extends OppositeDirection[Sell]
case object Buy extends Buy
trait Sell extends OppositeDirection[Buy]
case object Sell extends Sell
特质相反方向[D使用Miles Sabin的答案,你可以:

trait =!=[A, B]

implicit def neq[A, B] : A =!= B = null
implicit def neqAmbig1[A] : A =!= A = null
implicit def neqAmbig2[A] : A =!= A = null

sealed trait Direction
case object Buy     extends Direction
case object Sell    extends Direction
type Buy = Buy.type
type Sell = Sell.type

case class Trade[D <: Direction](id: Long, itemId: Long, quantity: Int)
case class Hedge[D <: Direction, O <: Direction](id: Long, itemId: Long, openingTrade: Trade[D], closingTrade: Trade[O])(implicit ev: D =!= O)

val trade1 = Trade[Buy.type](1,10,100)
val trade2 = Trade[Sell.type](2,10,-100)
trait=!=[A,B]
隐式def neq[A,B]:A=!=B=null
隐式定义neqAmbig1[A]:A=!=A=null
隐式定义neqAmbig2[A]:A=!=A=null
封闭性状方向
case对象扩展方向
case对象扩展方向
类型购买=购买类型
类型Sell=Sell.type
案例类交易[D=!=[A,A]
以及类型为[A]=>=!=[A,A]的方法neqAmbig2
匹配预期类型=!=[购买,购买]
val validHedge=对冲[买入,买入](563,10,交易1,交易1)

您可以使用它:

class TradeDirection[D <: Direction, Op <: Direction]

implicit val BuyToSell = new TradeDirection[Buy.type, Sell.type]
implicit val SellToBuy = new TradeDirection[Sell.type, Buy.type]

case class Hedge[D <: Direction, O <: Direction](id: Long, itemId: Long, openingTrade: Trade[D], closingTrade: Trade[O])(implicit d: TradeDirection[D, O])
class贸易方向[D]
abstract class OppositeDirection[D <: Direction](val opposite: D) extends Direction
abstract class Buy(opposite: Sell) extends OppositeDirection[Sell](opposite)
case object Buy extends Buy(Sell)
abstract class Sell(opposite: Buy) extends OppositeDirection[Buy](opposite)
case object Sell extends Sell(Buy)
trait =!=[A, B]

implicit def neq[A, B] : A =!= B = null
implicit def neqAmbig1[A] : A =!= A = null
implicit def neqAmbig2[A] : A =!= A = null

sealed trait Direction
case object Buy     extends Direction
case object Sell    extends Direction
type Buy = Buy.type
type Sell = Sell.type

case class Trade[D <: Direction](id: Long, itemId: Long, quantity: Int)
case class Hedge[D <: Direction, O <: Direction](id: Long, itemId: Long, openingTrade: Trade[D], closingTrade: Trade[O])(implicit ev: D =!= O)

val trade1 = Trade[Buy.type](1,10,100)
val trade2 = Trade[Sell.type](2,10,-100)
scala> val validHedge = Hedge[Buy, Sell](563,10,trade1,trade2)
validHedge: Hedge[Buy.type,Sell.type] = Hedge(563,10,Trade(1,10,100),Trade(2,10,-100))

scala> val invalidHedge = Hedge[Buy, Buy](563,10,trade1,trade1)
<console>:1: error: ambiguous implicit values:
 both method neqAmbig1 of type [A]=> =!=[A,A]
 and method neqAmbig2 of type [A]=> =!=[A,A]
 match expected type =!=[Buy,Buy]
       val validHedge = Hedge[Buy, Buy](563,10,trade1,trade1)
class TradeDirection[D <: Direction, Op <: Direction]

implicit val BuyToSell = new TradeDirection[Buy.type, Sell.type]
implicit val SellToBuy = new TradeDirection[Sell.type, Buy.type]

case class Hedge[D <: Direction, O <: Direction](id: Long, itemId: Long, openingTrade: Trade[D], closingTrade: Trade[O])(implicit d: TradeDirection[D, O])