2012-10-04 15 views
10

Jak porównać dwie wartości funkcji Scala dla równości. Przypadkiem użycia jest to, że mam listę funkcji, w których lista może zawierać duplikaty i chcę tylko wykonać każdą funkcję raz.Jak porównać wartości funkcji Scala dla równości

Jeśli mam:

scala> object A { 
    | def a {} 
    | } 
defined module A 

scala> val f1 = A.a _ 
f1:() => Unit = <function0> 

scala> val f2 = A.a _ 
f2:() => Unit = <function0> 

Gdy próbuję porównywać funkcję albo == lub eq, dostanę false w obu przypadkach:

scala> f1 == f2 
res0: Boolean = false 

scala> f1 eq f2 
res1: Boolean = false 
+10

Jest to ogólnie nie do rozwiązania problem. http://en.wikipedia.org/wiki/First-class_function#Equality_of_functions – missingfaktor

Odpowiedz

15

Krótka odpowiedź: To nie jest możliwe.

Dłuższa odpowiedź: Możesz mieć fabrykę funkcji, która zapewnia, że ​​"identyczne" funkcje są dokładnie tym samym obiektem. W zależności od architektury aplikacji może to jednak nie być możliwe.

8

Chcę nieco rozszerzyć odpowiedź Kima i podać przykład, jak osiągnąć ograniczoną porównywalność wartości funkcji.

Jeśli masz jakąś opisową definicję swojej funkcji, na tym opisie możesz sprawdzić równość. Na przykład, można zdefiniować klasę (nie klasa oo) z prostych funkcji arytmetycznych w następujący sposób:

sealed trait ArthFun extends (Double => Double) 
case class Mult(x: Double) extends ArthFun {def apply(y: Double) = x * y} 
case class Add(x: Double) extends ArthFun {def apply(y: Double) = x + y} 

Przy tej konfiguracji, gdzie ArthFun jest zdefiniowany przez jego klasy i członków, można sprawdzić dla równości wartości typu ArthFun po prostu przez równość obiektów zdefiniowaną przez klasę przypadków.

scala> trait ArthFun extends (Double => Double) 
defined trait ArthFun 

scala> case class Mult(y: Double) extends ArthFun { def apply(x: Double) = x * y; override def toString = "*" + y} 
defined class Mult 

scala> case class Add(y: Double) extends ArthFun { def apply(x: Double) = x + y; override def toString = "+" + y } 
defined class Add 

scala> Seq(Mult(5),Mult(4),Add(4),Add(3),Mult(5)).distinct 
res4: Seq[Product with ArthFun with Serializable] = List(*5.0, *4.0, +4.0, +3.0) 
+0

Podoba mi się ta odpowiedź, ale nie lubię konieczności definiowania klasy dla każdego operatora. Czy istnieje jakaś magia makro, która mogłaby to zrobić (przekształca wyrażenia w obiekty klasy z różnymi dekoracjami, takimi jak równość). – user48956

Powiązane problemy