假设我有两个对象A
和B
相同类型,方法doX
和doY
,两者都返回布尔值。
是否可以创建一种语言结构,例如and
或or
来执行以下操作?
A doX 和 doY B
通常,上述操作将通过以下方式完成
AdoX 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)
,并让 doX
和 doY
方法返回不同的类型,如果传递运算符(and
或 or
(或传递实际参数(B
(。
Scala 解析器翻译
A doX and doY B
自
A.doX(and).doY(B)
在考虑任何定义、类型信息等之前,因此您不能以任何方式影响此翻译。
但是你定义and
,A.doX(and)
将返回Boolean
(如果它编译(,并且不会有doY
方法。您可以使用隐式转换对其进行类型检查
implicit def wrap(x: Boolean): A.type = A
但这仍然没有得到预期的结果。
我不认为将and
作为宏也无济于事,但我可能忽略了那里的某些东西。