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



假设我有两个对象AB相同类型,方法doXdoY,两者都返回布尔值。

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

A doX 和 doY B

通常,上述操作将通过以下方式完成

A

doX B && A doY B

我想知道这是否可以如上所述缩短

我希望and推广到多种方法,而不仅仅是专门doA,所以我不能让它单独使用隐式

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

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),并让 doXdoY 方法返回不同的类型,如果传递运算符(andor (或传递实际参数(B(。

Scala 解析器翻译

A doX and doY B

A.doX(and).doY(B)

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

但是你定义andA.doX(and)将返回Boolean(如果它编译(,并且不会有doY方法。您可以使用隐式转换对其进行类型检查

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

但这仍然没有得到预期的结果。

我不认为将and作为宏也无济于事,但我可能忽略了那里的某些东西。

最新更新