Define antisymmetric function [duplicate]

This question already has an answer here:

Assume I'm trying to naively define an antisymmetric functionf[x_, y_] := -f[y, x]and assign it a value at some point f[1, 2] = 1;. After this, calling {f[1, 2], f[2, 1]} gives {1,-1} as desired. However, evaluating f[1,3] leads to an infinite recursion with result Hold[f[1, 3]].

My goal is to write a definition of f[x,y] in such a way that it tries both variants f[x,y] and -f[y,x] to see if a value is assigned for any of them. If it is, the function should evaluate to this value. If it isn't, then it should stay unevaluated but avoid the infinite loop.

marked as duplicate by Michael E2, MarcoB, Jens, AccidentalFourierTransform, halirutan♦Jul 10 '18 at 23:09

This works as requested:

Clear@f
Module[
{enabled = True},
f[x_, y_] /; enabled := Block[
{enabled = False},
With[
{res = f[y, x]},
-res /; res =!= Unevaluated@f[y, x]
]
]
]

Testing it:

f[1, 2]
(* f[1, 2] *)

f[2, 1] = 2
(* 2 *)

f[1, 2]
(* -2 *)

f[2, 1]
(* 2 *)

How

There are a few things that make this work:

• The Module/Condition(/;)/Block combination ensures that the definition is not infinitely reinserted into itself (you can remove the Module if you don't worry about the enabled flag colliding with anything
• In this setting, we can safely evaluate f[y,x] is safe.
• The last part is the second Condition(res =!= Unevaluated@…), which only applies the "flipping" of arguments if it actually evaluates to something else
• This works in my actual problem, great! The fact that x==Unevaluated[x] gives True seems counter-intuitive to me. I was thinking about how to check whether some change in expression really occurs, and this is the way to go. – Weather Report Jul 6 '18 at 6:36