As others have said, this is fundamentally impossible without additional constraints due to the undecidable nature of computation. Because it is undecidable in general, what is likely to happen even if you get kind of close is that you find a hack that kinda works in some cases, and it fails in difficult cases where people are really counting on it to be right.
Therefore, the standard approach if you want to compare computations is to define a canonical form and set of allowed operations and convert them to canonical form. (For instance, if it’s simply predicate logic, you can use deMorgan’s laws etc. to convert to prenex conjunctive normal form, which essentially eliminates arbitrary distinctions between how you write the same logical expression–and this is true even though truth is not computable (c.f. Godel incompleteness).)
Now, it is possible to intercept the expression with a macro and store, say, a hash or some representation of the whole expression tree as part of your object; if you replace class O(val f...)
with class O private (val f...)
plus object O { apply(f...)
it will be syntactically the same. But I very much discourage this. It will be weird and surprising; people will try to do trivial refactorings and everything will break.
So, no, don’t do it this way.
The way you have to do it is to structurally refer to the same computation.
For instance, if you have
val plusOne: Int => Int = _ + 1
val timesTwo: Int => Int => _ * 2
then you can store the function itself, and use reference equality eq
to make sure you’re calling the exact same one. If you have a function like
def auto[A](f: A => A)(using A): A = f(summon[A])
you can use it as an adaptor between context functions and regular ones.
But you’re better off not relying on things that make it look like you can write computations in multiple places and they will be correctly unified. This is in general very difficult to make good enough to not be more trouble than it’s worth, and Scala is not one of the languages that places this as a very high priority. Mathematica and other languages with stronger Lisp heritage generally provide more tools that help.