3
$\begingroup$

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.

$\endgroup$
10

1 Answer 1

4
$\begingroup$

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
$\endgroup$
1
  • $\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$ Commented Jul 6, 2018 at 6:36

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