如何根据Scala中的标记过滤条件

时间:2016-01-22 20:05:43

标签: scala types

给定一个具有一些'typed'标签的对象。 根据某些标准设计匹配器的实现的最佳方法是什么。问题实际上是以有效的方式利用类型系统。

这是我目前的尝试:

 object Criteria1 extends App {

  // Features
  // Feature A
  trait A
  case object A1 extends A
  case object A2 extends A

  // Feature B
  trait B
  case object B1 extends B
  case object B2 extends B

  // Criteria
  trait Criteria
  case class ACriteria(a: Set[A]) extends Criteria
  case class BCriteria(b: Set[B]) extends Criteria

  // Tag
  trait Tag
  case class ATag(a: A) extends Tag
  case class BTag(b: B) extends Tag


  def match_?(criterias: Set[Criteria], tags: Set[Tag]) : Boolean = {
    !criterias.exists {
      case ACriteria(v) => !v.map(value => ATag(value)).exists(tags.contains)
      case BCriteria(v) => !v.map(value => BTag(value)).exists(tags.contains)
    }
  }

  println(match_?(Set(ACriteria(Set(A1, A2))), Set(ATag(A1), ATag(A2)))) // true
  println(match_?(Set(ACriteria(Set(A1))), Set(ATag(A1), ATag(A2)))) // true
  println(match_?(Set(ACriteria(Set(A1, A2))), Set(ATag(A1)))) // true
  println(match_?(Set(), Set(ATag(A1)))) // true
  println(match_?(Set(ACriteria(Set(A1))), Set())) // false
  println(match_?(Set(ACriteria(Set(A1)), BCriteria(Set(B1))), Set(ATag(A1)))) // false
  println(match_?(Set(ACriteria(Set(A1)), BCriteria(Set(B1))), Set(BTag(B1)))) // false

}

但它很详细,而不是匹配方法中真正的DRY代码。

[更新] 当我考虑它时,似乎CriteriaTags类型不是很有用。这是一个更简单的版本,但由于Any而导致类型检查较少。有任何方法可以解决这个问题(也许Coproduct)?

object Criteria6 extends App {

  // Features
  // Feature A
  trait A
  case object A1 extends A
  case object A2 extends A

  // Feature B
  trait B
  case object B1 extends B
  case object B2 extends B

  def match_?(criterias: Set[Set[Any]], tags: Set[Any]) : Boolean = {
    !criterias.exists {
      v => !v.exists(tags.contains)
    }
  }

  println(match_?(Set(Set(A1, A2)), Set(A1, A2))) // true
  println(match_?(Set(Set(A1)), Set(A1, A2))) // true
  println(match_?(Set(Set(A1, A2)), Set(A1))) // true
  println(match_?(Set(), Set(A1))) // true
  println(match_?(Set(Set(A1)), Set())) // false
  println(match_?(Set(Set(A1), Set(B1)), Set(A1))) // false
  println(match_?(Set(Set(A1), Set(B1)), Set(B1))) // false
}

1 个答案:

答案 0 :(得分:0)

所以Type parameters似乎就是你想要的。

object Criteria6 extends App {

  // Features
  // Feature A
  trait A
  case object A1 extends A
  case object A2 extends A

  // Feature B
  trait B
  case object B1 extends B
  case object B2 extends B

  def match_?[T](criterias: Set[Set[T]], tags: Set[T]) : Boolean = {
    !criterias.exists {
      v => !v.exists(tags.contains)
    }
  }

  println(match_?(Set(Set(A1, A2)), Set(A1, A2))) // true
  println(match_?(Set(Set(A1)), Set(A1, A2))) // true
  println(match_?(Set(Set(A1, A2)), Set(A1))) // true
  println(match_?(Set(), Set(A1))) // true
  println(match_?(Set(Set(A1)), Set())) // false
  println(match_?(Set(Set(A1), Set(B1)), Set(A1))) // false
  println(match_?(Set(Set(A1), Set(B1)), Set(B1))) // false
}

这将带来额外的好处,您将无法使用不匹配的类型(A或B)调用match_?

我还没有得到的是Set(Set(A1, A2)), Set(A1, A2))应该表示需要验证的内容......