10
$\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$
  • $\begingroup$ Somewhat related: (334) $\endgroup$ – Mr.Wizard Sep 2 '17 at 11:58
8
$\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.

|improve this answer|||||
$\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

{}
|improve this answer|||||
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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