【问题标题】:Scala - Optional PredicateScala - 可选谓词
【发布时间】:2015-02-22 15:19:19
【问题描述】:

我被告知要使用这段有趣的代码,但我的用例要求它做的比目前可能的要多。

  implicit class Predicate[A](val pred: A => Boolean) {
    def apply(x: A) = pred(x)

    def &&(that: A => Boolean) = new Predicate[A](x => pred(x) && that(x))
    def ||(that: A => Boolean) = new Predicate[A](x => pred(x) || that(x))
    def unary_! = new Predicate[A](x => !pred(x))
  }

一些用例样板:

type StringFilter = (String) => Boolean

def nameFilter(value: String): StringFilter = 
    (s: String) => s == value

def lengthFilter(length: Int): StringFilter = 
    (s: String) => s.length == length


val list = List("Apple", "Orange", "Meat")
val isFruit = nameFilter("Apple") || nameFilter("Orange")
val isShort = lengthFilter(5)

list.filter { (isFruit && isShort) (_) }

到目前为止一切正常。但是说我想做这样的事情:

  val nameOption: Option[String]
  val lengthOption: Option[Int]

  val filters = {

    nameOption.map((name) =>
      nameFilter(name)
    ) &&
    lengthOption.map((length) =>
      lengthFilter(length)
    )
  }

  list.filter { filters (_) }

所以现在我需要&&Option[(A) => Boolean] 如果选项为无,那么只需忽略过滤器。

如果我使用类似的东西:

def const(res:Boolean)[A]:A=>Boolean = a => res

implicit def optToFilter[A](optFilter:Option[A => Boolean]):A => Boolean = optFilter match {
  case Some(filter) => filter
  case None => const(true)[A]
}

我遇到|| 的问题,其中一个过滤器设置为 true。我可以通过将 true 更改为 false 来解决这个问题,但是 && 也存在同样的问题。

我也可以采用这种方法:

  implicit def optionalPredicate[A](pred: Option[A => Boolean]): OptionalPredicate[A] = new OptionalPredicate(pred)

  class OptionalPredicate[A](val pred: Option[A => Boolean]) {
    def apply(x: A) = pred match {
      case Some(filter) => filter(x)
      case None => trueFilter(x)
    }

    def &&(that: Option[A => Boolean]) = Some((x: A) =>
      pred.getOrElse(trueFilter)(x) && that.getOrElse(trueFilter)(x))

    def ||(that: Option[A => Boolean]) = Some((x: A) =>
      pred.getOrElse(falseFilter)(x) || that.getOrElse(falseFilter)(x))
  }

  def trueFilter[A]: A => Boolean = const(res = true)

  def falseFilter[A]: A => Boolean = const(res = false)

  def const[A](res: Boolean): A => Boolean = a => res

但是当谓词不是选项的子类型时,必须将谓词转换为 OptionalPredicate 似乎本质上是错误的:

  implicit def convertSimpleFilter[A](filter: A => Boolean) = Some(filter)

允许:

ifFruit && isShort

我觉得 Optional 应该与 Predicate 无缝结合,同时遵循 DRY 原则。

【问题讨论】:

    标签: scala implicit-conversion implicit


    【解决方案1】:

    见下文 (UPD)

    如果能够将Option[Filter] 转换为Filter,那就太好了:

    def const(res:Boolean)[A]:A=>Boolean = a => res
    
    implicit def optToFilter[A](optFilter:Option[A => Boolean]):A => Boolean = optFilter match {
      case Some(filter) => filter
      case None => const(true)[A]
    }
    

    那么我们想使用任何可以转换为谓词的类型:

    implicit class Predicate[A, P <% A=>Boolean](val pred: P)
    

    (并将pred 的用法更改为(pred:A=&gt;Boolean)

    def &&[P2:A=>Boolean](that: P2) = new Predicate[A](x => (pred:A=>Boolean)(x) && (that:A=>Boolean)(x))
    

    UPD

    Option[A=&gt;Boolean] 将是真正的过滤器类型。

    implicit def convertSimpleFilter[A](filter:A=>Boolean)=Some(filter)
    
    implicit class Predicate[A](val pred: Option[A=>Boolean]){
      def &&(that:Option[A=>Boolean]) = Some((x:A) => pred.getOrElse(const(true))(x) && that.getOrElse(const(true))(x) )
      def ||(that:Option[A=>Boolean]) = Some((x:A) => pred.getOrElse(const(false))(x) || that.getOrElse(const(false))(x) )
    }
    

    【讨论】:

    • 如果 OP 想要完全忽略它,空过滤器不应总是评估为 true。否则,当存在空过滤器时,|| 将始终为真。
    • 我不知道你能做到&amp;&amp;[P2:A=&gt;Boolean](that: P2) 谢谢! m-z 上面说的是正确的,同样适用于false&amp;&amp;
    • 嗯,过滤器的基础似乎应该是Option[A=&gt;Boolean]。简单的过滤器应该可以转换成它,&amp;&amp;|| 方法应该考虑到过滤器可以省略。
    • "&amp;&amp;|| 应该考虑到过滤器可以省略。"没错。
    • 不错的更新。我试图将(A) =&gt; Boolean 保留为过滤器类型,并将Option[(A) =&gt; Boolean]` 转换为它。有没有办法做到这一点?我也想避免真假的事情,宁愿删除过滤器和运算符
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-29
    相关资源
    最近更新 更多