16
$\begingroup$

How do I get Mathematica to return a function call (conditionally) unevaluated? I expect this may use the slightly-mysterious Hold function.

As a toy example, suppose I want to define AlgebraicQ such that AlgebraicQ[x] returns True or False when Element[x, Algebraics] evaluates to True or False, but otherwise to returns AlgebraicQ[x], just like the other predicate functions do. (I can't just ask if Element[x, Algebraics] == True, because this is itself unevaluated.)

Edit: The first thing that came to mind didn't work, as you can see: With the definition AlgebraicQ(a_) := Element(a, Algebraics), the function AlgebraicQ[Pi+E] returns Element(E+Pi, Algebraics) instead of the desired AlgebraicQ(Pi+E). Parens used in place of brackets because of platform limitations.

I had tried this before posting, but on a recommendation I tried again with a fresh kernel (pictured above) with the same results. I also tried

AlgebraicQ[a_] := True /; Element[x, Algebraics]
AlgebraicQ[a_] := False /; ! Element[x, Algebraics]

based on an earlier suggestion but this seems not to work at all.


Final working solution

based on Szabolcs' answer:

AlgebraicQ[a_] := With[{result = Element[a, Algebraics]},
  result /; MatchQ[result, True | False]]

which tests as expected:

AlgebraicQ /@ {7, Pi, Pi + E}

Out[2]= {True, False, AlgebraicQ[E + Pi]}

$\endgroup$
  • $\begingroup$ A proper predicate does not have the behavior you request, but returns True or False for any expression it is given. $\endgroup$ – m_goldberg May 22 '14 at 13:54
  • $\begingroup$ @m_goldberg: The built-in AlgebraicIntegerQ has precisely the same behavior I'm describing. (How could a function possibly guarantee to return True or False when the answer is not even known to mathematicians?) $\endgroup$ – Charles May 22 '14 at 13:58
  • $\begingroup$ On OSX and v9 AlgebraicsQ[x_Real] := Element[x, Algebraics] works as you want. $\endgroup$ – gpap May 22 '14 at 14:07
  • $\begingroup$ @gpap: I can't imagine how, honestly. I mean, clearly that should work if I gave it a non-Real, but for a Real it should return Element[x, Algebraics] because that's what you're telling it to return. Very strange, I'd be interested to learn more about this case. $\endgroup$ – Charles May 22 '14 at 14:10
  • $\begingroup$ Sorry, when I say "as you want" I mean the example you referred to (these are evaluated on a fresh kernel). $\endgroup$ – gpap May 22 '14 at 14:13
15
$\begingroup$

Here's how this can be done:

ClearAll[algebraicQ]
algebraicQ[x_] := Module[{result},
  result = Element[x, Algebraics]; 
  result /; MatchQ[result, True | False]]

The key to these types of problems is usually a special use of Condition inside Block/Module/With which allows sharing localized variables between the condition and the body of Module.


At this point I should note that the convention seems to be that any function that ends in ...Q will always return either True or False. Consider EvenQ vs Positive. EvenQ[x], with x undefined, gives False. Positive[x] stays unevaluated. I know of only a very few edge cases which don't follow this. Naming this algebraicQ would violate that convention.

$\endgroup$
  • $\begingroup$ @Charles - How did you paste the image to SE? $\endgroup$ – eldo May 22 '14 at 14:58
  • $\begingroup$ @eldo See meta.mathematica.stackexchange.com/questions/5/… $\endgroup$ – Dr. belisarius May 22 '14 at 16:41
  • $\begingroup$ @eldo Use the image button in the editor to upload it. $\endgroup$ – Szabolcs May 22 '14 at 16:47
  • $\begingroup$ @belisarius - Thanks for pointing me to the SE-Uploader. This smart gadget should be mentioned somewhere in the SE-Help. $\endgroup$ – eldo May 22 '14 at 17:50
  • 2
    $\begingroup$ @Agreeing with the convention! I strongly hope that WRI sticks to this, minimizing headaches to sort out non-binary cases (True/False/unevaluated). $\endgroup$ – István Zachar Jul 5 '16 at 12:27
11
$\begingroup$

Your earlier approach would have worked if you had actually tested the argument to the function (a) rather than the undefined symbol x...

AlgebraicQ[a_] := True /; Element[a, Algebraics]
AlgebraicQ[a_] := False /; ! Element[a, Algebraics]
AlgebraicQ /@ {7, Pi, Pi + E}

(* {True, False, AlgebraicQ[E + Pi]} *)
$\endgroup$
  • $\begingroup$ Hah! So at least I wasn't too far off the mark, just careless. Thanks for pointing this out! $\endgroup$ – Charles May 22 '14 at 17:52

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.