18

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]}

J. M.'s missing motivation
  • 124,525
  • 11
  • 401
  • 574
Charles
  • 1,359
  • 8
  • 13
  • A proper predicate does not have the behavior you request, but returns True or False for any expression it is given. – m_goldberg May 22 '14 at 13:54
  • @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?) – Charles May 22 '14 at 13:58
  • On OSX and v9 AlgebraicsQ[x_Real] := Element[x, Algebraics] works as you want. – gpap May 22 '14 at 14:07
  • @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. – Charles May 22 '14 at 14:10
  • Sorry, when I say "as you want" I mean the example you referred to (these are evaluated on a fresh kernel). – gpap May 22 '14 at 14:13
  • @gpap: What do you get for AlgebraicQ /@ {7, Pi, Pi + E, I}? – Charles May 22 '14 at 14:15
  • @Charles I deleted because of good answers you've received and to not confise future visitors. To be honest, I don't remember for sure, maybe it's me who forgot about the Head. But you seems to be sure, mistakes happen to me and I don't have any reason not to trust you so: I'm sorry, I should be more careful. :) You may want to delete old not relevant comments too. – Kuba May 22 '14 at 18:42
  • @Charles sorry for the late response. Neither of these get evaluated (not the 7 either) to True or False. I don't understand why! – gpap May 23 '14 at 08:38

2 Answers2

18

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.

Szabolcs
  • 234,956
  • 30
  • 623
  • 1,263
12

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]} *)
Simon Woods
  • 84,945
  • 8
  • 175
  • 324