2
$\begingroup$

For example, I have defined a bunch of binary functions Sum1, Sum2, Prod1, Prod2, ... I want to make these functions associative, that is, the expression Sum1[a,b,c] will be evaluated as Sum1[Sum1[a,b],c]. I use the method here to achieve it:

Sum1[a_,b_,c__]:=Sum1[Sum1[a,b],c]

Now I want to do this to all of these binary functions without repeating it line by line (because there are too many of them). Is there a way to do it? I tried to do the following

Do[f[a_,b_,c__]:=f[f[a,b],c],{f,{Sum1,Sum2,Prod1,Prod2}}]

But after this, when I evaluate Sum1[a,b,c], it will return f[f[a,b],c]! In other words, the f after the := is not substituted by the instances from the list {Sum1,Sum2,Prod1,Prod2}.

$\endgroup$
2
  • 2
    $\begingroup$ Do[With[{f=f}, f[a_,b_,c__]:=f[f[a,b],c]],{f,{Sum1,Sum2,Prod1,Prod2}}] $\endgroup$
    – I.M.
    Commented Jun 16, 2022 at 4:25
  • $\begingroup$ @I.M. That works, but generally I think that if you feel like you need to use With[{f = f}, ...] you really should be using a Function and some mapping construct instead. $\endgroup$ Commented Jun 16, 2022 at 8:53

1 Answer 1

4
$\begingroup$

Try this:

install[f_Symbol]:=(f[a_,b_,c__]:=f[f[a,b],c];);
Scan[install,{Sum1,Sum2,Prod1,Prod2}];

You may also want to have a look at Flat and OneIdentity, see here, but using them can be tricky.

$\endgroup$
6
  • $\begingroup$ I have looked at Flat, but I am always confused about one thing - If f is flat, all it does is that f[f[a,b],c] will be converted to f[a,b,c]; I guess it is intended to be used for pattern matching and working with associative products of formal variables. However, if f is a concrete function (rather than a formal associative product), then Flat doesn't instruct f[a,b,c] to be evaluated as f[f[a,b],c]. $\endgroup$ Commented Jun 16, 2022 at 13:34
  • $\begingroup$ What precisely do you mean by a concrete function? For instance SetAttributes[f,{Flat,OneIdentity}]; f[a_,b_]:=a+b; f[3,4,5] does give 12. $\endgroup$
    – user293787
    Commented Jun 16, 2022 at 13:47
  • $\begingroup$ Oh I see, the issue seems deeper - This example above is fine, but mine is not, probably due to the fact that it is an operator on pure functions. Let's say the objects are infinite sequences a[n] (implemented as a pure function a) and we want to define the termwise sum f[a,b]:=a[#1]+b[#1]&; SetAttributes[f,{Flat,OneIdentity}]. Then f[a,b][3]' gives a[3]+b[3]` but f[a,b,c][3] just gives f[a,b,c][3] instead of the intended a[3]+b[3]+c[3]. $\endgroup$ Commented Jun 16, 2022 at 14:06
  • $\begingroup$ So f[a_,b_]:=(a[#]+b[#]&); SetAttributes[f,{Flat,OneIdentity}]; f[a,b,c][3] gives a[3]+b[3]+c[3]. You may have missed some underscores in the definition of f? $\endgroup$
    – user293787
    Commented Jun 16, 2022 at 14:16
  • 1
    $\begingroup$ After some retest, I find that the real problem seems to be that I need to set attributes before defining the function. The parenthesis doesn't matter. I need to run f[a_,b_]:=(a[#]+b[#]&); SetAttributes[f,{Flat,OneIdentity}] twice before it to work. Alternatively, if I do SetAttributes[f,{Flat,OneIdentity}]; f[a_,b_]:=(a[#]+b[#]&), then once is enough. $\endgroup$ Commented Jun 16, 2022 at 14:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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