Scala DSL "and" 用于链接多个命令的关键字

Scala DSL "and" keyword for chaining multiple commands

假设我有两个对象 AB 具有相同类型的方法 doXdoY,它们都是 return 布尔值。

是否可以创建一个语言结构,例如 andor 来执行以下操作?

A doX and doY B

通常上面的内容可以用

完成

A doX B && A doY B

我想知道是否可以像上面那样缩短

我希望 and 被泛化为多种方法,而不仅仅是具体 doA,所以我无法单独使用隐式。

Scala 解析器翻译

A doX and doY B

A.doX(and).doY(B)

在考虑任何定义、类型信息等之前,因此您不能以任何方式影响此翻译。

无论您如何定义 andA.doX(and) 都将 return Boolean(如果编译)并且不会有 doY 方法。您可以使用隐式转换对其进行类型检查

implicit def wrap(x: Boolean): A.type = A

但是这样还是没有得到想要的结果

我认为制作 and 宏也没有帮助,但我可能忽略了那里的某些东西。

所以事实证明语法可能并非完全不可能,但这仍然很丑陋。特别需要对您的 A class 进行一些重大修改。但这里有一个概念证明:

case class Bar(s: String)

trait PredicateArgumentContext[-T] {
  type Result
  def apply(f: Foo, p: Bar => Boolean, arg: T): Result
}

implicit val ApplyPredicateArgumentContext = new PredicateArgumentContext[Bar] {
  type Result = Boolean
  def apply(f: Foo, p: Bar => Boolean, arg: Bar): Boolean = p(arg)
}

sealed trait PredicateOperator

object and extends PredicateOperator
object or extends PredicateOperator

implicit val OperatorPredicateArgumentContext = new PredicateArgumentContext[PredicateOperator] {
  type Result = Foo
  def apply(f: Foo, p: Bar => Boolean, arg: PredicateOperator): Foo = arg match {
    case `and` => f.copy(predTransform = (p1 => b => p(b) && p1(b) ))
    case `or` => f.copy(predTransform = (p1 => b => p(b) || p1(b) ))
  }
}

case class Foo(predTransform: (Bar => Boolean) => (Bar => Boolean) = identity) {

  def doX[A](a: A)(implicit ctx: PredicateArgumentContext[A]): ctx.Result = {
    ctx.apply(this, predTransform(doXInternal _), a)
  }
  def doY[A](a: A)(implicit ctx: PredicateArgumentContext[A]): ctx.Result = {
    ctx.apply(this, predTransform(doYInternal _), a)
  }

  def doXInternal(b: Bar): Boolean = {
    b.s.size % 2 == 0
  }

  def doYInternal(b: Bar): Boolean = {
    b.s.size > 0
  }
}

val A = Foo()
val B = new Bar("asdf")

A doX and doY B // returns true

他们的关键见解是让 scala 将其解析为 A.doX(and).doY(B) 并且如果传递了一个运算符 (andor) 或者如果传递了实际参数 (B).