Re: Defining UpValues
- To: mathgroup at smc.vnet.net
- Subject: [mg110794] Re: Defining UpValues
- From: Leonid Shifrin <lshifr at gmail.com>
- Date: Wed, 7 Jul 2010 07:41:02 -0400 (EDT)
Istvan, Actually in that first letter that I never sent to you I had a solution which used a wrapper, so this is how I also would do that. The main problem to overcome in making your original code work was that the heads of expressions (even composite heads) evaluate before anything else (there is a separate recursion on heads in the case of nested heads), and evaluation of func[sys] in func[sys][args] is completely local in the sense that at the time func[sys] is evaluated, the evaluator has no idea whether this is a head of a larger expression or a stand-alone expression. I tried many different things but all of them failed in one way or another, until I realized that the evaluation stack can provide the non-local evaluation information that we needed. It looks like this trick can be used generally when we need to divert evaluation in a way that can not be achieved by the standard evaluation control (Evaluate, Unevaluated, Hold-attributes, etc), but one has to have a really good reason to do so! Best, Leonid 2010/7/6 Istv=E1n Zachar <replicatorzed at gmail.com> > Dear Leonid, > > thanks for the answer. Yes, I agree that the design is not the best in this > case, and to tell you the truth, > just after posting my question here I've decided - though I was a bit > dubious about it - to introduce the wrapper. > Now I'm much more confident with my choice as it seems to be the general > method to handle situations like this. > > The only problem (at the moment) with the wrapper is that previously the > (IRL) outcome of func was a list, while > now it has the wrapper as head, making ReplaceAll calls a bit harder to > implement (like > > {a, b} /. Wrapper[a -> 1, b -> 2] > > which gives an errormessage. But setting UpValues for Wrapper with > ReplaceAll does help here: > > Wrapper/: ReplaceAll[expr_, rep_Wrapper] :== ReplaceAll[expr, List @@ rep]; > > Anyway, your solution is impressive in its simplicity: I never would have > thought to fiddle with the evaluation stack, > but it's a very clever workaround! Though I won't use it, it still remains > to be a rather tricky intellectual achievement : ) > > Istvan > > > > On 2010.07.06. 14:12, Leonid Shifrin wrote: > > Hi Istvan, > > This was a tough one. Here is one way (it took me a while to figure it out, > first I thought it was > not possible, and almost sent you a long explanation why it is > impossible))): > > ClearAll[func]; > func[x_Integer] :== > x /; ! MemberQ[Stack[_], HoldForm[func[_Integer][args___]]]; > func /: func[sys_Integer][args___] :== sys + 1; > func[sys_Function] :== sys; > > > In[191]:== {func[1], func[1][2], func[# + 2 &], func[# + 2 &][2]} > > > Out[191]== {1, 2, #1 + 2 &, 4} > > I would still consider changing the design though, since this kind of > difficulties / workarounds usually > indicate to me that the design of the function in question is not well > thought over. For example, if > your sys is often supplied with additional optional arguments, you can > create a wrapper say sysData (or, just > a List) and store them there, like func[sysData[sys,opts___]], etc. > > Hope this helps. > > Regards, > Leonid > > > 2010/7/6 Istv=E1n Zachar <zac at freemail.hu> > >> Dear Group, >> >> consider the following code: >> >> func[sys_Integer] :== sys; >> func /: func[sys_Integer][args___] :== sys + 1; >> func[sys_Function] :== sys; >> >> { >> func[1], >> func[1][2], >> func[# + 2 &], >> func[# + 2 &][2] >> } >> >> Is there a way to define func such a way that when the main argument >> is an Integer, any further arguments are ignored? That is, to >> return: {1, 2, #1 + 2 &, 4} instead of {1, 1[2], #1 + 2 &, >> 4}. At present, the second function definition is basically ignored by >> the kernel. >> >> I am aware that func[sys_type, args___] would be the easiest way to >> use here, but in my real code >> 1. there is a large number of named options supplied with sys >> preventing (or at least making hard) the use of *any number* of >> optional second arguments; >> 2. sometimes the main call (func[sys]) is separated from the >> introduction of any optional argument (this is part of a GUI), which >> may cause calls like this: >> x == func[some_function]; ... (* calculations involving x *) ... ; >> y == x[2]; >> >> Thanks in advance, >> >> Istv==E1n >> >> >> >> >> >>