scala - Total Collections,拒绝不包括所有可能性的类型的集合

标签 scala haskell puzzle type-safety type-constraints

假设我们有以下类型:

sealed trait T
case object Goat extends T
case object Monk extends T
case object Tiger extends T

现在,您如何构建 T 的集合?使得每个子项中至少有一个 T出现在集合中,此约束在编译时强制执行?与此相反的集合:
val s:Seq[T] = Seq(Goat)

编译,这个:
val ts:TotalSeq[T] = TotalSeq(Goat, Goat, Tiger)

才不是。我在上面使用过 Scala,但我也很乐意看到其他语言的解决方案。

(如果我的话有点不对,请原谅我;我感冒了,今天正在用拼图自娱自乐。)

最佳答案

它看起来像具有通用类型约束的构建器模式:http://www.tikalk.com/java/blog/type-safe-builder-scala-using-type-constraints

就像是:

sealed trait TBoolean
sealed trait TTrue extends TBoolean
sealed trait TFalse extends TBoolean

class SeqBuilder[HasGoat <: TBoolean, HasMonk <: TBoolean, HasTiger <: TBoolean] private (seq: Seq[T]) {

  def +=(g: Goat.type) = new SeqBuilder[TTrue, HasMonk, HasTiger](g +: seq)

  def +=(m: Monk.type) = new SeqBuilder[HasGoat, TTrue, HasTiger](m +: seq)

  def +=(t: Tiger.type) = new SeqBuilder[HasGoat, HasMonk, TTrue](t +: seq)

  def build()(implicit evg: HasGoat =:= TTrue, evm: HasMonk =:= TTrue, evt: HasTiger =:= TTrue) = seq
}


object SeqBuilder {
  def apply = new SeqBuilder(Seq())
}

用法:
scala> SeqBuilder() + Goat + Tiger + Monk build()
res21: Seq[T] = List(Monk, Tiger, Goat)

scala> SeqBuilder() + Goat + Goat + Monk build()
<console>:34: error: Cannot prove that Nothing =:= TTrue.
       SeqBuilder() + Goat + Goat + Monk build()
                                         ^

如果您想要的实例数量增加,您可以尝试使用 HMap

其他类似方法:幻影类型:http://james-iry.blogspot.com/2010/10/phantom-types-in-haskell-and-scala.html

另一种方法是询问为什么需要所有 3 个对象。假设您想在 seq 具有所有三个时进行操作,那么您可以执行以下操作:
object SeqBuilder {
  val all = Seq(Goat, Monk, Tiger)

  def apply(t: T*)(onAll: Seq[T] => Unit)(onViolation: => Unit) = {
     val seq = Seq(t:_*)
     if(all forall seq.contains) onAll(seq)
     else onViolation
  }
}

这样,如果没有提供所有必需的 Ts,则不会调用 onAll 函数,否则调用违规函数

关于scala - Total Collections,拒绝不包括所有可能性的类型的集合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6216385/

相关文章:

java - 强制 kafka 消费者轮询延迟最高的分区

scala - Spark DataFrame 列名称未传递给从属节点?

haskell - 有类似 `map2::(i -> a) -> (i -> b) -> [i] -> [(a,b)]` 的东西吗?

android - 如何检测我正在制作的安卓游戏的获胜条件

解决 N Queens Domination 难题的算法

益智游戏算法

scala - NULL 指针异常,同时在 foreach() 中创建 DF

java - 在电梯应用程序中将 Scala 版本更新为 2.10.0

list - 让 Haskell 中的递归

haskell - Writer monad 中的记忆化