开发者

Can I automatically lazily evaluate function parameters in Mathematica?

In Mathematica, I'd like to do something along the lines of:

f[Rational[a_, b_], Rational[c_, d_]] := {a+c, b+d}

But if I evaluate it with expressions of the following form I get the wrong result:

In: f[Rational[50, 100], Rational[4, 10]]
Out: {3, 7}
(* Expected: 54 / 110 ->  27 / 55 *)

Is there any way I can force Mathematica to stop simplifying the expression immediately? I can just do a hold on whatever I pass in, then have the function in question just call ReleaseHold[..] on whatever what was passed in.

This solution is very ugly though, and I don't want to have to do this. I know some functions in Mathematica automatically hold whatever is passed in and delay evaluating it for some reason or another, and I would like to do this here.

In short: How can I force Mathematica to l开发者_如何学Cazily evaluate something being passed into a function without having to manually hold it?


In the standard evaluation procedure, each argument of a function is evaluated in turn. This is prevented by setting the attributes HoldFirst, HoldRest and HoldAll. These attributes make Mathematica "hold" particular arguments in an unevaluated form.

http://reference.wolfram.com/legacy/v5/TheMathematicaBook/PrinciplesOfMathematica/EvaluationOfExpressions/2.6.5.html

e.g.

  • SetAttributes[yourFunction, HoldFirst]
  • http://reference.wolfram.com/mathematica/ref/HoldFirst.html

The docs say any auto-Held arguments are automatically evaluated the first time you use them in the function body. However if for some reason you want to continue working with the argument in the Hold form (e.g. if you'd like to do pattern-matching and rewriting on the unevaluated form of the expression), then perhaps you can re-Hold it.


Using the HoldAll attribute ninjagecko mentioned I was able to craft a solution.

There was actually another issue going on that I wasn't able to see immediately. Specifically, my function wasn't pattern matching as I thought it would be.

I thought my initial issue was simply that Mathematica was automatically simplifying my expressions and I needed to lazily evaluate the parameters being passed in for the correct behavior.

In reality, I forgot that there are multiple ways of representing expressions in Mathematica. As a toy example consider the following function which extracts the numerator and denominator of a fraction:

ExtractNumDem[Fraction[a_, b_]] := {a, b}
(* Already incorrect, ExtractNumDem[4 / 100] gives {1, 25} *)

Just adding the HoldAll (Or HoldFirst even) attribute results in another issue:

SetAttributess[ExtractNumDem, HoldAll];
ExtractNumDem[4 / 100] (* Gives ExtractNumDem[4 / 100] *)

The expression 4 / 100 is actually evaluating to Times[4, Power[100, -1]]. To fix this second issue I had to add a definition for fractions that look like that:

ExtractNumDem[Times[a_, Power[b_, -1]] := {a, b}
ExtractNumDem[4/100] (* Now gives {4, 100} *)

My solution to fixing the issue in my original answer applied the same exact principle. Here's some code to actually see the issue I was running into:

ClearAll[ExtractNumDem]

ExtractNumDem[Rational[a_, b_]] := {a, b}
ExtractNumDem[4 / 100]

SetAttributes[ExtractNumDem, HoldAll];
ExtractNumDem[4 / 100]

ExtractNumDem[Times[a_, Power[b_, -1]]] := {a, b}
ExtractNumDem[4/100]
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜