Scala - 前缀一元运算符

wen*_*wen 10 logic scala notation unary-operator

我最近给了Scala第二次机会,并从我总是实现的项目开始(在函数或伪函数语言中):命题逻辑(以及后来的谓词逻辑)的自动推理器.

现在,我试图尽可能地在语言本身中获得命题逻辑的符号,并且我已经实现了这一点 - 使用隐式转换(String - > Atom):

("A" and "B") implies "C"
Run Code Online (Sandbox Code Playgroud)

函数"和"和"暗示"(以及"或"和"等价")是调用相关案例类构造函数的简单方法.但是,在实现"not"时,我会遇到以下两种符号中的任何一种:

("A" and "B").not
Not("A" and "B")
Run Code Online (Sandbox Code Playgroud)

有没有办法欺骗Scala接受所需的:

not("A" and "B")
Run Code Online (Sandbox Code Playgroud)

最好不要将"Not"类重命名为"not",因为我可能希望将来称之为"¬"或其他东西.

Pau*_*ane 22

我注意到另一个问题的答案,看起来人们可以在运营商名称前加上unary_你想要做的事情.(见unary_!.)

编辑:本文确认了语法.

  • 特别是`prefix_`只适用于`!`,`~`,`+`和`-`. (18认同)
  • @Paul:我认为这不是那么随意.我想,没有这个限制会让解析变得非常痛苦.你不知道`foo bar`是否应该解析为`foo.bar()`或`bar.unary_foo()`直到在类型检查之后(如果两者都可能,你还需要规则来决定选择哪一个). (14认同)
  • 但这不适用于自定义运算符名称。即你不能定义`unary_not` 来获得前缀“not”-operator。 (2认同)
  • @ Dennetik:如果你选择`!`而不是'not`,请记住scala还允许你定义`&&`,`||`和` - >`,所以你不必混合运算符和单词. (2认同)

sep*_*p2k 14

您可以not在单个对象上定义方法,如下所示:

object Logic {
  def not(x:Expr) = Not(x)
}
import Logic._
not("A" and "B")
Run Code Online (Sandbox Code Playgroud)

(这里Expr应该是共同的超类And,Or,NotAtom)

编辑:这是一个例子,说明如何只使用一次导入:

object Logic {
  abstract class Expr {
    def and(e: Expr) = Conjunction(this, e)
    def or(e: Expr) = Disjunction(this, e)
    def implies(e: Expr) = Implication(this, e)
  }
  case class Conjunction(e1: Expr, e2: Expr) extends Expr
  case class Disjunction(e1: Expr, e2: Expr) extends Expr
  case class Implication(e1: Expr, e2: Expr) extends Expr
  case class Negation(e: Expr) extends Expr
  case class Atom(name: String) extends Expr

  def not(e: Expr) = Negation(e)
  implicit def string2atom(str: String) = Atom(str)
}

// use site
import Logic._
not("A" and "B") implies (not("A") or not("B"))
Run Code Online (Sandbox Code Playgroud)

  • @Dennetik:如果您只是将所有内容都放入Logic对象中,那么您只需要使用`import Logic._`来使用您的类. (2认同)

Dan*_*ral 8

为什么Not而不是not?没有什么可以阻止你这样做:

object not {
  def apply(expr: T) = ...
}
Run Code Online (Sandbox Code Playgroud)

然后使用not("A" and "B").

  • @ErikAllik因为在2010年没有包对象. (2认同)
  • 好点子!没有意识到这一点——谢谢:) PS 但是,您今天会使用它来定义“not(expr: T)”吗? (2认同)

Eri*_*lun 5

截至2014年2月,我认为not在表达式上定义前缀运算的最简洁方法,同时避免各种额外的瑕疵/包装,将直接在包范围内声明函数,以及所有其他函数,类,类型等:这是通过定义一个包对象来完成的(Scala不允许你只将函数放在.scala文件的根级别(我很想知道为什么 - 它只是为了跟随Java的脚步?)).

package org.my.logiclib

implicit class Atom(s: String) { ... }
class MyType1
class MyType2

object `package` {
  def not(expr: Expr) = ...
}
Run Code Online (Sandbox Code Playgroud)

这样,做import org.my.logiclib._就会导入一切,包括not().

以上是相同的

package org.my

package logiclib {
  implicit class Atom ...
  ...

  def not(expr: Expr) = ...
}
Run Code Online (Sandbox Code Playgroud)