5
$\begingroup$

I have some objects represented as follows:

Object[data, param]

data is a list of numbers, param is an integer.

Somewhere in my program, I need to do something like that:

pseed = N[seed, prec];

In this context, seed can be either a number or my object Object. When seed is an Object I want N to be applied only to data list. But N is applied to param too, which I want always to be an Integer.

Of course, I could write:

pseed = If[Head[seed] === Object,
  MapAt[N[#, prec]&, seed, 1],
  N[seed, prec]
];

But I believe, this would make my code messy and hard to read. Therefore I decided to do something like that:

Unprotect[N];
N[Object[data_List, param_Integer], p_] := Object[N[data, p], param];
Protect[N];

Than the simple N[seed, prec] should work whether seed is Obj or Number. However, I get the following error:

$RecursionLimit::reclim: Recursion depth of 1024 exceeded.

I cannot understand, where do I have a recursion?

Thanks in advance!


Update. I have received the answer from Wolfram Support:

I understand you believe you've found a bug with N.

In this case, Mathematica is behaving as designed. N is a fairly complicated function and changing its definition arbitrarily by using the Unprotect function can lead to unforeseen consequences. While the definition we provide works as designed, the change you made to it does not behave as you expect. The TagSet and TagSetDelayed function was supplied to address just the kind of problem you are trying to solve. Try

In[1]:= f/:Verbatim[N][f[arg1_,otherArgs__]]:=f[N[arg1],otherArgs]
In[2]:= N[f[1,2]]
Out[2]= f[1.,2]

Alternatively, you can avoid the need for the Verbatim function by injecting a secondary step:

In[1]:= f/:NN[f[arg1_,args__]]:=f[NN[arg1],args]
In[2]:= NN[arg1_]:=N[arg1]
In[3]:= NN[f[1,2]]
Out[3]= f[1.,2]

Setting up the dummy function can even allow you to avoid the need for the TagSetDelayed:

In[1]:= NN[f[arg1_,args__]]:=f[N[arg1],args]
In[2]:= NN[f[1,2]]
Out[2]= f[1.,2]

For more on TagSet, TagSetDelayed and Verbatim, please see

http://reference.wolfram.com/language/ref/TagSet.html

http://reference.wolfram.com/language/ref/TagSetDelayed.html

The question seems to be solved. Thank everybody for participation!

$\endgroup$
  • 2
    $\begingroup$ Why don't define it explicitly? pSeedFunc[data_Object, prec_?NumericQ] := Sequence[data, N@prec]; pSeedFunc[nbr_?NumericQ, prec_?NumericQ] := Sequence[N@nbr, N@prec]; pSeedFunc[Object[caca, 1], 1] $\endgroup$ – Dr. belisarius Nov 28 '14 at 15:36
  • $\begingroup$ @belisarius Oh, I haven't thought about that! Actually, it would solve my problem, but I have many places in my code, where I need to take N from an Object or Number (not only in the given example). That's why I would like to add my own definition of function N. $\endgroup$ – Kirill Mingulov Nov 28 '14 at 17:32
  • 1
    $\begingroup$ @Melkogotto I changed the title of the question to emphasize the essence of the problem. If you think it is inappropriate, you can rollback the edit. $\endgroup$ – Alexey Popkov Nov 28 '14 at 18:53
  • $\begingroup$ @Melkogotto It seems you have discovered a long-standing bug in N. I suggest you to report it to the technical support (with a link to this thread). I have added the bugs tag. $\endgroup$ – Alexey Popkov Nov 28 '14 at 20:02
  • 1
    $\begingroup$ @AlexeyPopkov I've reported the issue. I let you know, when I'll receive support answer. $\endgroup$ – Kirill Mingulov Nov 28 '14 at 20:29
10
$\begingroup$

The recursion limit error which you observe looks like a bug in N. Here is a shorter code to reproduce the issue:

N[obj[args__]] := obj[args]    
N@obj[1, 2, 3]
During evaluation of In[2]:= $RecursionLimit::reclim: Recursion depth of 1024 exceeded. >>

obj[1, 2, 3]

In the comments Oleksandr R. provided a workaround via combined usage of Verbatim and UpValues:

ClearAll[Object];
Object /: 
 Verbatim[N][Object[arg1_, arg2_, argRest__], 
  Narg : _ | PatternSequence[]] := 
 Object[arg1, N[arg2, Narg], argRest]

If you wish N to affect only the first argument of Object, it is sufficient just to set the NHoldRest attribute:

ClearAll[Object];
SetAttributes[Object, NHoldRest]

Now

N@Object[1, 1]
Object[1., 1]
$\endgroup$
  • $\begingroup$ Wow, what a nice attribute! This will probably solve my problem. Don't you know, what can I do, if my data list is somewhere between other parameters, like: Object[param1, data, param2]? I can place my list at the first place in Object, but maybe I can somehow avoid this. $\endgroup$ – Kirill Mingulov Nov 28 '14 at 17:35
  • $\begingroup$ In this case you will not have such a simple and elegant solution and probably will need to go through UpValues in a way similar to what you showed in your question. Other way is shown by @belisarius in his comment. $\endgroup$ – Alexey Popkov Nov 28 '14 at 18:00
  • 1
    $\begingroup$ Sorry for disinformation but with UpValues I get the recursion limit error too. The idea was: Object /: N[Object[arg1_, arg2_, argRest__]] := Object[arg1, N@arg2, argRest]. I do not know why with N this gives the recursion limit error, it does work with other heads. $\endgroup$ – Alexey Popkov Nov 28 '14 at 18:23
  • 3
    $\begingroup$ Object /: Verbatim[N][Object[arg1_, arg2_, argRest__]] := Object[arg1, N[arg2], argRest] $\endgroup$ – Oleksandr R. Nov 28 '14 at 18:53
  • 2
    $\begingroup$ The Trace is not very enlightening, but I think this may have to do with the recursive behavior of N. When called on any expression, it applies itself to the parts first (and the parts of the parts, &c.) in an effort to numericize the whole. Here it seems that it gets stuck while repeatedly trying to numericize the second argument. Possibly a bug in N? By the way, a better pattern is Object /: Verbatim[N][Object[arg1_, arg2_, argRest__], Narg : _ | PatternSequence[]] := Object[arg1, N[arg2, Narg], argRest]. This handles the argument of N correctly. $\endgroup$ – Oleksandr R. Nov 28 '14 at 19:16

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.