18
$\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$
8
  • $\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, 2014 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, 2014 at 13:58
  • $\begingroup$ On OSX and v9 AlgebraicsQ[x_Real] := Element[x, Algebraics] works as you want. $\endgroup$
    – gpap
    May 22, 2014 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, 2014 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, 2014 at 14:13

2 Answers 2

18
$\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$
5
  • $\begingroup$ @Charles - How did you paste the image to SE? $\endgroup$
    – eldo
    May 22, 2014 at 14:58
  • $\begingroup$ @eldo See meta.mathematica.stackexchange.com/questions/5/… $\endgroup$ May 22, 2014 at 16:41
  • $\begingroup$ @eldo Use the image button in the editor to upload it. $\endgroup$
    – Szabolcs
    May 22, 2014 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, 2014 at 17:50
  • 3
    $\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$ Jul 5, 2016 at 12:27
12
$\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$
1
  • $\begingroup$ Hah! So at least I wasn't too far off the mark, just careless. Thanks for pointing this out! $\endgroup$
    – Charles
    May 22, 2014 at 17:52

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.