11
$\begingroup$

Is there a convenient way to find out which DownValues is used when calling a function? As an example, consider the following function:

abs[Complex[0,n_]] := Complex[0,Abs[n]]

abs[n_?NumberQ] := Sign[n] n

abs[n_?NumericQ] /; MemberQ[{-1,0,1}, Sign[n]] := Sign[n] n

abs[x_] /; Internal`SyntacticNegativeQ[x] := -x

abs[x_] := x

which is just some random code. Now, I want to know which DownValues fired when I evaluate abs[N@I]? Obviously, this example is simple enough that I can figure out which DownValues would fire by inspection, assuming the DownValues occur in the order listed above. However, suppose there are many more DownValues, or suppose you don't to spend time perusing the DownValues to figure out which one would fire for a particular input. Is there some simple function that will give me which DownValues has fired?

$\endgroup$
1
  • $\begingroup$ Somewhat related: (334) $\endgroup$
    – Mr.Wizard
    Sep 2, 2017 at 11:58

2 Answers 2

9
$\begingroup$

Here is a simple utility function that I use all the time:

SetAttributes[ExtractDownValues, HoldAll]

ExtractDownValues[sym_[args__]] := ExtractDownValues[sym,args]
ExtractDownValues[sym_,args__] := Cases[
    DownValues[sym], _[h_, _] /; MatchQ[Unevaluated[sym[args]], h]
]

For your example we find:

ExtractDownValues @ abs[N @ I]

{HoldPattern[abs[n_?NumberQ]] :> Sign[n] n, HoldPattern[abs[x_]] :> x}

I keep the full list of matching DownValues because the real matching DownValues can be hard to determine syntactically if any of the DownValues use Condition.

$\endgroup$
4
$\begingroup$

This could be useful.

I attempted to handle Condition; maybe it can be cleaned up some.

SetAttributes[capture, HoldFirst]

capture[expr : h_[___]] :=
  Module[{dv, rls, i = 1, cond},
    SetAttributes[cond, HoldAll];
    cond[a_, b_] := Condition @@ Hold[a, b];
    cond[a_] := a;

    dv = DownValues[h];
    rls = Cases[dv, (L_ :> Verbatim[Condition][R_, C_] | R_) :> cond[L, C] -> i++];
    AppendTo[rls, _ -> {}];

    dv[[ Replace[Unevaluated[expr], rls] ]]
  ]

Test:

abs[N@I] // capture
HoldPattern[abs[n_?NumberQ]] :> Sign[n] n

Right-hand-side condition:

foo[a_] := bar /; a

foo[True]  // capture
foo[False] // capture
HoldPattern[foo[a_]] :> bar /; a

{}
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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