Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I am quite new to Mathematica and not completely familiar with functional programming. I am currently working with a function (call it foo) and wish to change its behaviour, for example, by adding 1 to its output. Obviously writing

foo = (foo[#]+1)&;

or

foo[x_] := foo[x] + 1;

leads to an infinite recursion as soon as I try to evaluate the function. To be more explicit, if at the beginning foo[1] returns 1 and foo[2] returns 3, I would like the output to be 2 and 4 respectively after the change.

Is there any way to easily obtain this behaviour with Mathematica?

I apologize if the question is a duplicate, but I did not find anything similar already posted.

share|improve this question
1  
Why not defining a foo2[x_] = foo[x] + 1 ? –  b.gatessucks Mar 21 '13 at 16:08
    
The line of code is thought to be inside a loop and I need to, so to say, update the function before iterating. –  Stefano Mar 21 '13 at 16:14
add comment

2 Answers

up vote 8 down vote accepted

If you absolutely have to use the same name for the function, and add new behavior, then you have several options. A special device invented for this sort of situations is called Villegas-Gayley technique. In this particular case, it will look like

ClearAll[foo,inFoo];
foo[n_] := 2*n - 1;

foo[x_] /; ! TrueQ[inFoo] := Block[{inFoo = True}, foo[x] + 1]

where the last definition is the one which alters the behavior. You can test:

foo /@ {1, 2}

(* {2, 4} *)

However, this won't always work. For example, this won't work if your function has been defined specifically on these values:

ClearAll[foo];
foo[1] = 1;
foo[2] = 3;

Adding this definition now

foo[x_] /; ! TrueQ[inFoo] := Block[{inFoo = True}, foo[x] + 1]

won't help:

foo /@ {1, 2}

(* {1, 3} *)

The reasons for that have to do with the relative specificity of various patterns, and the fact that a function defined on specific values has a different (hash-table - based) representation which is hard to override.

In this case, I suggest to use a rather heavy-handed approach I described here. Using functions from it, we have:

withUserDefs[
  foo, 
  {foo[x_] /; ! TrueQ[inFoo] := Block[{inFoo = True}, foo[x] + 1]},
  foo /@ {1, 2}
]

(* {2, 4} *)

However, best would be to reconsider your design and needs, since chances are that you don't really need any of these methods, and can find a solution by more traditional means.

share|improve this answer
    
Thank you very much for the quick answer, which solved the issue. Is it right to say that the trick is able to "freeze" further evaluations of the function because after the first call to foo the flag inFoo is set to True and therefore the condition ! TrueQ[inFoo] necessary to evaluating foo cannot be further met? –  Stefano Mar 22 '13 at 0:18
    
@Stefano Yes, this is exactly what happens. Glad I could help. Thanks for the accept. –  Leonid Shifrin Mar 22 '13 at 0:30
    
Sorry for writing again, but checking further the results, I noticed that some problems are still around. If I try ClearAll[foo] foo[n_] := 2*n - 1; For[i = 0, i < 10, i++, ClearAll[inFoo]; foo[x_] /; ! TrueQ[inFoo] := Block[{inFoo = True}, foo[x] + 1]; Print[foo[2]] ] the output is 3, 4, 4, 4... with the function being updated only once. Is this the behaviour expected? –  Stefano Mar 22 '13 at 1:07
    
@Stefano Yes, it is expected. Try to figure out on your own why this is so. I also think that whatever your problem is, you should be able to solve it without the rather heavy machinery I described in my post. –  Leonid Shifrin Mar 22 '13 at 2:08
add comment

Do you mean you need to update the definition of the function in terms of the previous definition? I do not get infinite recursion when doing the following:

Mathematica graphics

Make sure x has no assigned value when you do this, and use = (not :=) to allow the previous definition to expand.

All this said, it is not a good idea to do this in most cases, and there should be alternative solutions (depending on the problem).

share|improve this answer
    
Does this answer your question at all? I'm not sure I understand it. Leonid's answer is interesting and useful, but it's not really a basic one. I thought it's educational to add this very basic comment. –  Szabolcs Mar 21 '13 at 20:11
    
Thank you very much indeed. –  Stefano Mar 22 '13 at 0:22
    
Thank you very much for the remark. Actually, I meant the definition with := instead of =. Indeed, the last does not seem to give problems in the simple example above. I am quite new to functional programming in general. I am try to implement some kind of fixed point algorithm where the unknown are functions: what design would you suggest in this case? (obviously the issue above is an outcome of my background in procedural programming) –  Stefano Mar 22 '13 at 0:29
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.