Scala DSL "and" 用于链接多个命令的关键字
Scala DSL "and" keyword for chaining multiple commands
假设我有两个对象 A
和 B
具有相同类型的方法 doX
和 doY
,它们都是 return 布尔值。
是否可以创建一个语言结构,例如 and
或 or
来执行以下操作?
A doX and doY B
通常上面的内容可以用
完成
A doX B && A doY B
我想知道是否可以像上面那样缩短
我希望 and
被泛化为多种方法,而不仅仅是具体 doA
,所以我无法单独使用隐式。
Scala 解析器翻译
A doX and doY B
到
A.doX(and).doY(B)
在考虑任何定义、类型信息等之前,因此您不能以任何方式影响此翻译。
无论您如何定义 and
,A.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)
并且如果传递了一个运算符 (and
或 or
) 或者如果传递了实际参数 (B
).
假设我有两个对象 A
和 B
具有相同类型的方法 doX
和 doY
,它们都是 return 布尔值。
是否可以创建一个语言结构,例如 and
或 or
来执行以下操作?
A doX and doY B
通常上面的内容可以用
完成A doX B && A doY B
我想知道是否可以像上面那样缩短
我希望 and
被泛化为多种方法,而不仅仅是具体 doA
,所以我无法单独使用隐式。
Scala 解析器翻译
A doX and doY B
到
A.doX(and).doY(B)
在考虑任何定义、类型信息等之前,因此您不能以任何方式影响此翻译。
无论您如何定义 and
,A.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)
并且如果传递了一个运算符 (and
或 or
) 或者如果传递了实际参数 (B
).