假设我有两个相同类型的对象A
和B
,方法doX
和doY
,两者都返回布尔值。
是否可以创建一个语言结构,例如and
或or
,以执行以下操作?
doX和doY B
通常上述内容将通过
完成doX B&&一个doY B
我想知道这是否可以缩短如上所述
我希望and
能够针对多种方法进行推广,而不仅仅是doA
,所以我不能单独使用隐式方法。
答案 0 :(得分:2)
事实证明,语法可能并非完全不可能,但这仍然非常难看。特别需要对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
方法,则返回不同的类型1}})或传递实际参数(or
)。
答案 1 :(得分:1)
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
宏也有帮助,但我可能会忽视那些东西。