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.


This works as requested:

  {enabled = True},
  f[x_, y_] /; enabled := Block[
    {enabled = False},
      {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 *)


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
| improve this answer | |
  • $\begingroup$ 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. $\endgroup$ – Weather Report Jul 6 '18 at 6:36

Not the answer you're looking for? Browse other questions tagged or ask your own question.