在Scala中创建中缀运算符

15

我正在尝试将一些Haskell代码翻译成Scala,但我在创建中缀运算符方面遇到了困难。

例如,在Haskell中我定义了这个中缀运算符:

infix 1 <=>                          // this specifies the operator precedence
(<=>) :: Bool -> Bool -> Bool        // this is the type signature of this operator (it says, it takes two Boolean values and returns a Boolean value)
x <=> y = x == y                     // this is the definition of the operator, it is mimicking the behaviour of the logical implication 'if-and-only-if'

现在,假设我有两个布尔值,p和q,其中p == True,q == False,则p <=> q将返回False。

我的问题是如何将其翻译为Scala。我查看了Odersky的《Scala编程》中定义的Rational类,并尝试跟随示例。这是我所达到的程度:

class Iff (b : Boolean){
  def <=> (that : Boolean) : Boolean = {
    this.b == that
  }
}

val a = new Iff(true)
println(a.<=>(false))  // returns false as expected

我可能没有用惯用的Scala实现这个,所以我正在寻求帮助。

我的问题是:

  1. 我在Scala中是否按照惯例实现了这个?如果没有,那么在Scala中最好的方法是什么?
  2. 我是否必须创建该类来定义此运算符?也就是说,我能否像上面的Haskell代码中那样定义一个独立的方法?
  3. 如何在Scala中指定运算符的固定级别?也就是它的优先级。

有趣的是,Scala中的运算符优先级是固定的。 - J. Abrahamson
1个回答

17

您可以定义隐式类

implicit class Iff(val b: Boolean) extends AnyVal {
  def <=>(that: Boolean) = this.b == that
}

现在你可以不使用new来调用它:

true <=> false // false
false <=> true // false
true <=> true  // true

1
创建一个值类(extends AnyVal)的原因是什么?它也可以没有。 - ccheneson
5
是的,即使没有它也可以工作,但是根据文档,通过将类扩展为AnyVal,您可以避免在运行时分配对象,而是将其表示为其底层值 - 在构造函数中指定的值。因此,在这种情况下,运行时,您的类“Iff”将被表示为“Boolean”。 - goral
5
既然您将问题标记为Haskell,那么这可能有助于您的理解:在Scala中扩展AnyVal基本上与在Haskell中使用newtype而不是data是相同的。它在编译时创建一个包装器,但在运行时并不存在。 - Tobias Brandt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接