Prev: FindRoot with parameterized interpolated function
Next: Copying and Pasting from a Grid with Dividers
From: István Zachar on 5 Jul 2010 21:14 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
From: Leonid Shifrin on 7 Jul 2010 07:39 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(a)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(a)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 >> >> >> >> >> >>
From: Leonid Shifrin on 7 Jul 2010 07:43 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(a)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 > > > > > > > --001636c5a74c2f189a048ab6f60d Content-Type: text/html; charset="ISO-8859-1" Content-Transfer-Encoding: quoted-printable X-Sun-Content-Length: 2579 Hi Istvan,<br><br>This was a tough one. Here is one way (it took me a while= to figure it out, first I thought it was <br>not possible, and almost sent= you a long explanation why it is impossible))):<br><br>ClearAll[func];<br> func[x_Integer] :=<br> x /; ! MemberQ[Stack[_], HoldForm[func[_Integer= ][args___]]];<br>func /: func[sys_Integer][args___] := sys + 1;<br>func[s= ys_Function] := sys;<br><br><br>In[191]:= {func[1], func[1][2], func[# = + 2 &], func[# + 2 &][2]}<br> <br><br>Out[191]= {1, 2, #1 + 2 &, 4}<br><br>I would still consider c= hanging the design though, since this kind of difficulties / workarounds us= ually<br>indicate to me that the design of the function in question is not = well thought over. For example, if <br> your sys is often supplied with additional optional arguments, you can crea= te a wrapper say sysData (or, just <br>a List) and store them there, like f= unc[sysData[sys,opts___]], etc.<br><br>Hope this helps.<br><br>Regards,<br> Leonid <br> <br><br><div class="gmail_quote">2010/7/6 Istv=E1n Zachar <span dir="lt= r"><<a href="mailto:zac(a)freemail.hu">zac(a)freemail.hu</a>></span><br= ><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; bord= er-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;"> Dear Group,<br> <br> consider the following code:<br> <br> func[sys_Integer] := sys;<br> func /: func[sys_Integer][args___] := sys + 1;<br> func[sys_Function] := sys;<br> <br> {<br> func[1],<br> func[1][2],<br> func[# + 2 &],<br> func[# + 2 &][2]<br> }<br> <br> Is there a way to define func such a way that when the main argument<br> is an Integer, any further arguments are ignored? That is, to<br> return: {1, 2, #1 + 2 &, 4} instead of {1, 1[2], #= 1 + 2 &,<br> 4}. At present, the second function definition is basically ignored by<br> the kernel.<br> <br> I am aware that func[sys_type, args___] would be the easiest way to<br> use here, but in my real code<br> 1. there is a large number of named options supplied with sys<br> preventing (or at least making hard) the use of *any number* of<br> optional second arguments;<br> 2. sometimes the main call (func[sys]) is separated from the<br> introduction of any optional argument (this is part of a GUI), which<br> may cause calls like this:<br> x = func[some_function]; ... (* calculations involving x *) ... ;= <br> y = x[2];<br> <br> Thanks in advance,<br> <br> Istv=E1n<br> <br> <br> <br> <br> <br> <br> </blockquote></div><br> --001636c5a74c2f189a048ab6f60d--
From: István Zachar on 7 Jul 2010 07:44
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(a)freemail.hu <mailto:zac(a)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 b= y > 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 > > > > > > > |