如何订购密封特征?
How to do ordering of a sealed trait?
我有一个由 "state machine" ( "flow chart" )
定义的分布式系统
每个系统在共享状态中写入状态 "log"
我将每个状态表示为密封特征的一部分,并为该状态"status"
我想"merge/reduce"到一个代表当前进度的状态。
(有一些放宽,因为并非所有人都必须成功才能成功完成最终状态)
有2个sealed traits代表流量:
sealed trait System
case object A extends System
case object B extends System
case object C extends System
...
sealed trait Status
case object Pending extends Status
case object InProgress extends Status
case object Success extends Status
case object Fail extends Status
日志:
A, Success
B, Fail
C, Pending
...
...
现在有一组规则可以用来定义单个状态降低
基本上它给出了优先级
A < B < C, ... < Z
和
Pending < InProgress < Success < Fail
所以如果状态为:
(A, Success)
对比 (C, Pending)
我想减少到(C,Pending)
如果
(A,Success)
对比 (B, Fail)
我想减少到(B, Fail)
在我的案例中,我可以将其建模为简单的整数比较(可能带有我明确测试的异常值)
我不清楚如何制作密封的特性comparible/orderable这会让我的生活更轻松
遵循这些原则就足够了:
def reduce(states: Seq[(System,Status)]) : (System,Status) = {
states.order... {left.system < right.system) && (a.status < b.status) ... possibly another ordering test ....}.tail // take the last one in the ordering
}
你可以定义一个scala.math.Ordering[Status]
:
object StatusOrdering extends Ordering[Status] {
def compare(x: Status, y: Status): Int =
(x, y) match {
// assuming that the ordering is Pending < InProgress < Success < Fail...
case (_, _) if (x eq y) => 0
case (Pending, _) => -1
case (_, Pending) => 1
case (InProgress, _) => -1
case (_, InProgress) => 1
case (Success, _) => -1
case (_, Success) => 1
case _ => 0 // (Fail, Fail)
}
在你的reduce
中,你可以
import StatusOrdering.mkOrderingOps
你的 Status
对象将因 <
和朋友而丰富。
也可以让你的 trait
扩展 Ordered[Status]
,它定义了特征中的规范排序:
sealed trait OrderedStatus extends Ordered[OrderedStatus] {
def compare(that: OrderedStatus): Int =
(this, that) match {
case (x, y) if (x eq y) => 0
case (Qux, _) => -1
case (_, Qux) => 1
case (Quux, _) => -1
case (_, Quux) => 1
case _ => 0
}
}
case object Qux extends OrderedStatus
case object Quux extends OrderedStatus
case object Quuux extends OrderedStatus
那么你不必导入 mkOrderingOps
,但我个人不喜欢在 compare
方法中向前使用扩展 case objects
(以及样板 compare
在每种情况下 object 更糟)。
一种方法是在 Map
秒内定义 System
和 Status
的优先级,然后通过 [=16] 定义 (System, Status)
的顺序=]:
val syMap: Map[System, Int] = Map(A->1, B->2, C->3)
val stMap: Map[Status, Int] = Map(Pending->1, InProgress->2, Success->3, Fail->4)
implicit val ssOrdering: Ordering[(System, Status)] =
Ordering.by{ case (sy, st) => (syMap.getOrElse(sy, 0), stMap.getOrElse(st, 0)) }
import ssOrdering._
(A, Success) < (C, Pending)
// res1: Boolean = true
(A, Success) < (B, Fail)
// res2: Boolean = true
(C, Pending) < (B, Fail)
// res3: Boolean = false
请注意,在上面的示例代码中,不匹配的默认值 System/Status
设置为 0
(最低优先级)。可以根据需要将它们设置为任何其他值。
减少 Seq
的 (System, Status)
秒:
def ssReduce(ss: Seq[(System, Status)])(implicit ssOrd: Ordering[(System, Status)]) : (System, Status) = {
import ssOrd._
ss.reduce((acc, t) => if (t < acc) acc else t ) // Or simply `ss.max`
}
ssReduce(Seq((A, Success), (C, Pending), (B, Fail)))
// res4: (System, Status) = (C,Pending)
考虑 enumeratum-cats CatsOrderValueEnum
定义顺序的方法
import cats.Order
import enumeratum.values._
import cats.instances.int._
sealed abstract class Status(val value: Int) extends IntEnumEntry
object Status extends CatsOrderValueEnum[Int, Status] with IntEnum[Status] {
case object Pending extends Status(1)
case object InProgress extends Status(2)
case object Success extends Status(3)
case object Fail extends Status(4)
val values = findValues
}
object AdtOrder extends App {
import Status._
println(Order[Status].compare(Pending, Fail))
}
输出
-1
哪里
libraryDependencies ++= Seq(
"com.beachape" %% "enumeratum" % "1.5.13",
"com.beachape" %% "enumeratum-cats" % "1.5.15"
)
我有一个由 "state machine" ( "flow chart" )
定义的分布式系统每个系统在共享状态中写入状态 "log"
我将每个状态表示为密封特征的一部分,并为该状态"status"
我想"merge/reduce"到一个代表当前进度的状态。
(有一些放宽,因为并非所有人都必须成功才能成功完成最终状态)
有2个sealed traits代表流量:
sealed trait System
case object A extends System
case object B extends System
case object C extends System
...
sealed trait Status
case object Pending extends Status
case object InProgress extends Status
case object Success extends Status
case object Fail extends Status
日志:
A, Success
B, Fail
C, Pending
...
...
现在有一组规则可以用来定义单个状态降低
基本上它给出了优先级
A < B < C, ... < Z
和
Pending < InProgress < Success < Fail
所以如果状态为:
(A, Success)
对比 (C, Pending)
我想减少到(C,Pending)
如果
(A,Success)
对比 (B, Fail)
我想减少到(B, Fail)
在我的案例中,我可以将其建模为简单的整数比较(可能带有我明确测试的异常值)
我不清楚如何制作密封的特性comparible/orderable这会让我的生活更轻松
遵循这些原则就足够了:
def reduce(states: Seq[(System,Status)]) : (System,Status) = {
states.order... {left.system < right.system) && (a.status < b.status) ... possibly another ordering test ....}.tail // take the last one in the ordering
}
你可以定义一个scala.math.Ordering[Status]
:
object StatusOrdering extends Ordering[Status] {
def compare(x: Status, y: Status): Int =
(x, y) match {
// assuming that the ordering is Pending < InProgress < Success < Fail...
case (_, _) if (x eq y) => 0
case (Pending, _) => -1
case (_, Pending) => 1
case (InProgress, _) => -1
case (_, InProgress) => 1
case (Success, _) => -1
case (_, Success) => 1
case _ => 0 // (Fail, Fail)
}
在你的reduce
中,你可以
import StatusOrdering.mkOrderingOps
你的 Status
对象将因 <
和朋友而丰富。
也可以让你的 trait
扩展 Ordered[Status]
,它定义了特征中的规范排序:
sealed trait OrderedStatus extends Ordered[OrderedStatus] {
def compare(that: OrderedStatus): Int =
(this, that) match {
case (x, y) if (x eq y) => 0
case (Qux, _) => -1
case (_, Qux) => 1
case (Quux, _) => -1
case (_, Quux) => 1
case _ => 0
}
}
case object Qux extends OrderedStatus
case object Quux extends OrderedStatus
case object Quuux extends OrderedStatus
那么你不必导入 mkOrderingOps
,但我个人不喜欢在 compare
方法中向前使用扩展 case objects
(以及样板 compare
在每种情况下 object 更糟)。
一种方法是在 Map
秒内定义 System
和 Status
的优先级,然后通过 [=16] 定义 (System, Status)
的顺序=]:
val syMap: Map[System, Int] = Map(A->1, B->2, C->3)
val stMap: Map[Status, Int] = Map(Pending->1, InProgress->2, Success->3, Fail->4)
implicit val ssOrdering: Ordering[(System, Status)] =
Ordering.by{ case (sy, st) => (syMap.getOrElse(sy, 0), stMap.getOrElse(st, 0)) }
import ssOrdering._
(A, Success) < (C, Pending)
// res1: Boolean = true
(A, Success) < (B, Fail)
// res2: Boolean = true
(C, Pending) < (B, Fail)
// res3: Boolean = false
请注意,在上面的示例代码中,不匹配的默认值 System/Status
设置为 0
(最低优先级)。可以根据需要将它们设置为任何其他值。
减少 Seq
的 (System, Status)
秒:
def ssReduce(ss: Seq[(System, Status)])(implicit ssOrd: Ordering[(System, Status)]) : (System, Status) = {
import ssOrd._
ss.reduce((acc, t) => if (t < acc) acc else t ) // Or simply `ss.max`
}
ssReduce(Seq((A, Success), (C, Pending), (B, Fail)))
// res4: (System, Status) = (C,Pending)
考虑 enumeratum-cats CatsOrderValueEnum
定义顺序的方法
import cats.Order
import enumeratum.values._
import cats.instances.int._
sealed abstract class Status(val value: Int) extends IntEnumEntry
object Status extends CatsOrderValueEnum[Int, Status] with IntEnum[Status] {
case object Pending extends Status(1)
case object InProgress extends Status(2)
case object Success extends Status(3)
case object Fail extends Status(4)
val values = findValues
}
object AdtOrder extends App {
import Status._
println(Order[Status].compare(Pending, Fail))
}
输出
-1
哪里
libraryDependencies ++= Seq(
"com.beachape" %% "enumeratum" % "1.5.13",
"com.beachape" %% "enumeratum-cats" % "1.5.15"
)