Scala中是否存在函数相等的概念?
scala> def foo(x: Int) = x + 1
foo: (x: Int)Int
scala> def bar(x: Int) = x + 1
bar: (x: Int)Int
所以我无法在函数上调用==
。
scala> foo == bar
<console>:10: error: missing arguments for method foo;
follow this method with `_' if you want to treat it as a partially applied
function
foo == bar
^
除了验证所有 x 的foo(x)
== bar(x)
(不知道该怎么做)之外,我还能如何验证相等性?
答案 0 :(得分:5)
你真的不希望==
产生除false之外的任何内容,因为==
表示“具有相同的内存地址”,除非它是专门为该类定义的。毕竟,
scala> class A
scala> (new A) == (new A)
res0: Boolean = false
如果Function1
尝试提供==
的实施,则不清楚它会检查什么。所有可能的投入都有相同的结果同样的行为?相同的字节代码?
如果你想要一个具有良好定义的相等操作的函数类,你必须自己编写它:
class Adder(private val toAdd: Int) extends (Int => Int) {
override def apply(n: Int) = n + toAdd
override def equals(other: Any) = other match {
case o: Adder => this.toAdd == o.toAdd
case _ => false
}
}
然后你可以这样做:
scala> val foo = new Adder(1)
foo: Adder = <function1>
scala> val bar = new Adder(1)
bar: Adder = <function1>
scala> foo(2)
res4: Int = 3
scala> foo == bar
res5: Boolean = true
要获得更简单的解决方案,只需将您的课程设为case class
,即可免费提供equals
和hashCode
个实施:
case class Adder(private val toAdd: Int) extends (Int => Int) {
override def apply(n: Int) = n + toAdd
}
答案 1 :(得分:2)
假设存在这样的功能。
/** Decides whether `f1` and `f2` compute the same function. */
def functionEquals[A, B](f1: A => B, f2: A => B): Boolean
然后我们可以写下这个:
/** Decides whether `m` halts on input `x`. */
def halts[X](m: X => Unit, x: X): Boolean =
!functionEquals[Unit, Unit](
{ _ => while(true)() },
{ _ => m(x) }
)
当然,这是不可能的。
答案 2 :(得分:1)
首先,在可以计算的函数上没有一般的相等关系(因为函数本质上是无限集)。根据函数的表示,您可能会获得弱相等性(即,当结果为true时两个参数相等但在结果为false时它们也可能相等)。
在scala中你可能会这样做:
scala> (foo _).equals((bar _ ))
res3: Boolean = false
scala> (foo _) == ((foo _ ))
res5: Boolean = false
函数背后的下划线是区分零参数应用程序和函数值的语法要求。 equals方法(作为==)是一般对象相等,因此只是一个by-reference比较。每个评估都会产生一个新的引用(闭包实例)。所以平等很弱:
scala> val x = foo _
x: Int => Int = <function1>
scala> x.equals(x)
res7: Boolean = true
答案 3 :(得分:1)
Scala中是否存在函数相等的概念?
简短而有些无益的答案是否定的,你不能写下因赖斯定理而导致的函数的一般情况平等。推断两个函数是否相等需要证明函数中的逻辑,这可以在某些情况下完成,但不是一般的。
作为一个愚蠢的例子,考虑到这样一个事实:我们知道任何偶数(可表示为2 * n)数模2都会留下零余数,这是小学数学的微不足道的结果,但它是编译器需要的一段知识。必须假设foo == bar。
def foo(x: Int) = (x*2) % 2
def bar(x: Int) = 0
Scala的类型系统可以使用更复杂的类型编码其中一些属性,但通常不会。
答案 4 :(得分:1)
TLDR:是的,有功能平等的概念。但它是基本的对象引用平等,因此效益很小
问题1:您可以在函数值上调用== - 但defs不是val。
你不能在defs上调用任何方法(除了函数应用程序的特殊情况) - 因为它们不是对象实例(vals)。但你可以通过调用它们(应用)将它们转换为val,为缺少的参数指定_(创建部分应用的函数):
val fooVal = foo(_) // type is Function1[Int, Int] (from def foo = ...)
val barVal = bar(_) // ditto
fooVal == barVal // == works (returns false)
foo(_) == bar(_) // ditto
问题2:Function1没有定义equals()覆盖
Function1
定义不会覆盖equals
:https://github.com/scala/scala/tree/v2.10.3/src/library/scala/Function1.scala#L1。 Function1
扩展AnyRef
,从而继承== / equals / eq的功能:
Any.==
只需委托Any.equals
。 AnyRef.equals
只需委托AnyRef.eq
,即检查对象引用的等效性。 因此,Function1。==表示函数对象(val)引用的等价:
val fooVal = foo(_)
val foo2Val = foo(_)
val foo3Val = fooVal
val barVal = bar(_)
fooVal == barVal // returns false
fooVal == foo2Val // returns false (different objects)
fooVal == foo3Val // returns true (same object)
问题3:当然,您可以延长Function1
- 但是如何定义有意义的equals
???
abstract class MyFunction1[A,B] extends Function1[A,B] {
// abstract because apply needs to be defined later for each different function
override def equals(other: Any) =
// your smart definition here!
}
val myDoIt1 = new MyFunction1[Int, Int] {
def apply(x: Int): Int = x + 1
}
val myDoIt2 = new MyFunction1[Int, Int] {
def apply(y: Int): Int = y + 2 -1
}
// What equals logic could make these two equate?
// Would need compilation smarts & logic matching!
// Fall-back to class comparison would only work with extensive code design restrictions.