1
$\begingroup$

It's isn't a big deal, but when I run the following I don't get the output I expect. After discussing this in the comments it appears it has to do with being an atomic expression.

FullForm @ Replace[
 Rational[1, 2], {
  x_Integer :> a[x]
  },
 {0, Infinity}
 ]

Here is a a solution I have worked out:

FullForm @ Replace[
  Rational[1, 2], {
   x_Integer :> a[x],
   Rational[x_Integer, b_Integer] :> Rational[a @ x, a @ b]
   },
  {0, Infinity}
  ]

Is there a better solution?

$\endgroup$
  • 1
    $\begingroup$ Not the downvoter but I think the issue here with trying to use Replace on the Rational is that a Rational is atomic (Depth of 1) so the Replace is not going to examine the numerator or denominator of the Rational, regardless of the levels you specify. It only sees the rational as a whole. $\endgroup$ – IPoiler Sep 4 '15 at 16:47
  • $\begingroup$ @It'sPronouncedOiler It doesn't look like it is a bug, what is the best fix? $\endgroup$ – William Sep 4 '15 at 16:51
  • $\begingroup$ Well I always hate to give the answer that the solution you're unsatisfied with is the best one, but that seems to be the case here. To me, it seems without specifying the Rational in the pattern that MMA doesn't have access to the deeper elements of the number (the numerator and denominator) , even though we know it's comprised of as many as 2 integer numbers. I noted the same behavior if you try to do it with Complex instead of Rational, which MMA also treats as atomic. We know the Complex is comprised of 2 Reals but w/o a similar pattern, MMA won't access them. $\endgroup$ – IPoiler Sep 4 '15 at 17:10
  • 5
    $\begingroup$ How about Hold[Rational[1, 2]] /. x_Integer :> a[x] // ReleaseHold ? $\endgroup$ – ilian Sep 4 '15 at 17:20
  • $\begingroup$ Your desired replacement could be done inside Hold, before Rational has had a chance to evaluate and become atomic. $\endgroup$ – ilian Sep 4 '15 at 18:04
3
$\begingroup$

Another way to deconstruct Rational is to use Numerator and Denominator:

Replace[Rational[1, 2], {x_Rational :> Rational[a@ Numerator@x, a@ Denominator@x]}]
(*  Rational[a[1], a[2]]  *)

Or perhaps a fraction is desired:

Replace[Rational[1, 2], {x_Rational :> a@ Numerator@x / a@ Denominator@x}]
(*  a[1]/a[2]  *)

While it might be considered by some to be more expressive than the OP's replacement Rational[x_Integer, b_Integer] :> Rational[a@x, a@b], it is also slightly slower (roughly 1 second per 10^6 rational numbers).

The same sort of thing can be done with the atomic Complex:

Replace[Complex[1, 2], {x_Complex :> Complex[a@ Re@x, a@ Im@x]}]
(*  Complex[a[1], a[2]]  *)

Replace[Complex[1, 2], {x_Complex :> a@ Re@x + a@ Im@x * I}]
(*  a[1] + I a[2]  *)

Note: I don't believe there's anything wrong with Rational[a[1], a[2]], but it is not atomic. It also does not behave as a number or an algebraic fraction in expressions. It seems to be an expression on its way to being a rational number, as soon as the values of a[1] and a[2] become integers, unless a[2] becomes 0. It is similar with Complex[a[1], a[2]].

|improve this answer|||||
$\endgroup$
4
$\begingroup$

A better solution is the one given by ilian in the comments. For example,

a[1] = 5; a[2] = 42;
Hold[Rational[1, 2]] /. x_Integer :> a[x] // ReleaseHold
5/42
|improve this answer|||||
$\endgroup$
2
$\begingroup$

Based on what I guess (by reading the comments and edit history) OP is trying to accomplish, it may also be done with the Box way:

Rational[1, 2] //
   MakeBoxes //
  # /. x_String /; StringMatchQ[x, DigitCharacter ..] :> 
     RowBox[{"a", "[", x, "]"}] & //
 MakeExpression
|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.