7
$\begingroup$

I'm trying to define a function f, such that

f[a_]:=a;

f[f[a__]]:=f[a];

Then, I tried to evaluate f[x,y]. Since f[x,y] satisfies none of these two patterns, it is expected that the result will be just f[x,y]. Nevertheless, in fact, the result is

Hold[f(a,b)]

and I get a error message:

$IterationLimit::itlim: Iteration limit of 4096 exceeded. >>

It seems quite confusing. How could this happen?

$\endgroup$
  • $\begingroup$ Greetings! To make the most of Mma.SE please take the tour now. Help us to help you, write an excellent question. Edit if improvable, show due diligence, give brief context, include minimum working examples of code and data in formatted form. As you receive give back, vote and answer questions, keep the site useful, be kind, correct mistakes and share what you have learned. $\endgroup$ – rhermans Nov 2 '15 at 14:31
  • 4
    $\begingroup$ You're looking for the Flat attribute. $\endgroup$ – rcollyer Nov 2 '15 at 14:33
  • 1
    $\begingroup$ Also, take a look at ?f. Another way to achieve the desired result would be f[Hold@f[a__]]:=f[a];. $\endgroup$ – Graumagier Nov 2 '15 at 14:40
  • $\begingroup$ @rcollyer,@Graumagier.Thanks for all of your help. I changed my code by replacing the second line by SetAttributes[f,Flat]. However, the problem remained. $\endgroup$ – Wen Chern Nov 2 '15 at 15:20
  • $\begingroup$ I'm not really sure Flat does what you want to do. Did you try f[Hold@f[a__]]:=f[a];? Also take care to clear all definitions/restart the kernel. $\endgroup$ – Graumagier Nov 2 '15 at 15:24
6
$\begingroup$

Note the following

a=3;
g[a]=2;
g//Definition

g[3]=2

We see that the definition g[3]=2 was stored, rather than g[a]=2. The argument of g, which is a, is evaluated before the definition is made.

The same happens in your code. f[a__] evaluates to a__ before the definition is made.

f//Definition
f[a_]:=a
f[a__]:=f[a]

I like the following solution

f4[a_] := a;
f4[HoldPattern@f4[a__]] := f4[a];

Another solution relies on using Unevaluated in a strange and AFAIK undocumented way, like this

f2[a_] := a;
f2[Unevaluated@f2[a__]] := f2[a];
f2 // Definition
f2[f2[a__]]:=f2[a] 
f2[a_]:=a

I kind of like this too, because it allows you to make the definition you want to make, without HoldPattern.

$\endgroup$
  • $\begingroup$ I have quited the kernel before runing these two lines of codes. How could the arguments be evaluated? $\endgroup$ – Wen Chern Nov 2 '15 at 15:27
  • $\begingroup$ @WenChern it is just what Mathematica does. I suppose the case of the example of g was the main case that was focused on in making this decision. $\endgroup$ – Jacob Akkerboom Nov 2 '15 at 15:33
  • $\begingroup$ The problem arises if you evaluate f[a_]=a prior to f[f[a__]]=f[a], because first f[a_] gets "replaced" with a, and then f[f[a__]]=f[a] evaluates to f[a__]=f[a]. $\endgroup$ – Graumagier Nov 2 '15 at 15:33
  • $\begingroup$ @Graumagier yes, this is essentially Chris Degnens solution. My own solution is something that may be nice to see for more experienced users. I suppose it also explicitly reminds you of the problem, which can be nice. $\endgroup$ – Jacob Akkerboom Nov 2 '15 at 15:36
  • $\begingroup$ Sure, your solution is definitely more robust. I just tried to explain the problem to Wen Chern, but your comment was put up first ;) $\endgroup$ – Graumagier Nov 2 '15 at 15:39
4
$\begingroup$

You can get the expected output by defining the functions in reverse order.

f[f[a__]] := f[a]
f[a_] := a

f[x, y]

f[x, y]

$\endgroup$
  • $\begingroup$ Thank you very much. Though I don't know how this method works, it does solve the problem. $\endgroup$ – Wen Chern Nov 2 '15 at 15:37
  • $\begingroup$ @WenChern it changes the order in which the patterns are tested. Since f[f[a]] matches both f[a_] and f[f[a__]], you need to change the order they're stored in (cf. DownValues, and the answers). This is most easily effected by changing the order they're declared in. Note, however, there is a notion of specificity, where more specific patterns are tested before more general ones. In this case, though, they're equally general. $\endgroup$ – rcollyer Nov 2 '15 at 16:14
  • 1
    $\begingroup$ @rcollyer unless I am mistaken, this is not what is going on. The pattern f[f[a__]] is more specific than f[a_], so in this sense the order should not matter. In the example f7[a_] := a; f7[{a__}] := f7[a]; the DownValues are automatically sorted for this reason. The reason for the trouble is that in the other order of evaluation, there is an unexpected evaluation of a pattern. Please see my answer. $\endgroup$ – Jacob Akkerboom Nov 2 '15 at 16:40
  • $\begingroup$ @JacobAkkerboom you're correct. I misread DownValues@f, completely missing the transformation. $\endgroup$ – rcollyer Nov 2 '15 at 16:48
  • 2
    $\begingroup$ @rcollyer to be honest this is something I could easily have missed while writing code myself. It is nice to be reminded of this danger IMO. $\endgroup$ – Jacob Akkerboom Nov 2 '15 at 17:10
3
$\begingroup$

Jacob gives a good exposition on different methods that work. But, to avoid any possibility of ambiguity, I would go with something very different

f[a_] := a
f[q_f] := q

which is correctly ordered

DownValues@f
(* {HoldPattern[f[q_f]] :> q, HoldPattern[f[a_]] :> a} *)
$\endgroup$
0
$\begingroup$

It looks like your double uderscore (BlankSequence) in the second definition matches things like x,y. For example:

f[a__] := 10*a;
f[3, 2, 4]
240
$\endgroup$
  • $\begingroup$ Sure it does, but by Wen Chern's intuition neither f[f[a__]] nor f[a_] should match f[x,y] (and they don't actually). Only in the above combination they do. $\endgroup$ – Graumagier Nov 2 '15 at 14:50
  • $\begingroup$ @Graumagier I guess I don't really understand what the desired result is. $\endgroup$ – Mitchell Kaplan Nov 2 '15 at 14:57
  • $\begingroup$ As I understand it the expression f[x,y] should be returned unevaluated because it is not of the form f[f[a__]] (a function inside a function). $\endgroup$ – Graumagier Nov 2 '15 at 14:58

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.