I'm trying to define a function that replaces certain expressions that appear when calculating scattering amplitudes (not important). Basically, I have a function spab[a_,c_,b_], where a,b are single elements and c is a list with at most two levels. For example, I can write

spab[1,{2,3,4},5]; spab[4,{3},9]; spab[5,{{3,4},{7,6},2},1];

etc. I have another function spbb[a_,c_,b_] with the same type of arguments and a last function spa[a_,b_] with only single element arguments. What I want to do is to substitute spab[a_,c_,b_] for the product

(*Sum over all i*) spa[a,c[[1,i]]]*spbb[c[[1,i]],c[[2;;]],b].

In other words, I want to take the first element of the list c and set it as the single element argument for the spa and spbb functions. If c[[1]] is itself a list, then I want to take each element of this sublist, apply the procedure I just described and then sum over these elements. I'll write up some examples of what I want the result to look like:

spab[5,{{3,4},{7,6},2},1]->spa[5,3]*spbb[3,{7,6},2},1] + spa[5,4]*spbb[4,{7,6},2},1]

I though I could achieve this with something like:


In my mind, this first creates a list of products spa[a,c[[1,i]]]*spbb[c[[1,i]],c[[2;;]],b] by using the Map command with the list c[[1]] and then sums over al the elements. However, the result is:

During evaluation of In[19]:= Part::partd: Part specification c[[1]] is longer than depth of object.

During evaluation of In[19]:= Part::take: Cannot take positions 2 through -1 in c.

During evaluation of In[19]:= Part::pkspec1: The expression spa[a,1] spbb[1,c[[2;;All]],b] cannot be used as a part specification.

During evaluation of In[19]:= Part::pkspec1: The expression spa[5,1] spbb[1,{{7,6},2},1] cannot be used as a part specification.

Out[19]= (spa[5, {{3, 4}, {7, 6}, 2}] spbb[{{3, 4}, {7, 6}, 2}, {{7, 6}, 2}, 1])[[spa[5, 1]spbb[1, {{7, 6}, 2}, 1]]]

What do all these error messages mean? Why do I get this weird result, and what is the factor between [[ ]] that appears at the very end? If someone culd help me make things clear and fix this, I would very much appreciate it.

  • $\begingroup$ The reason that you're getting the errors is that the expression Plus[spa[a, #]*spbb[#, c[[2 ;;]], b] & /@ c[[1]]] gets evaluated before being used in the replacement rule. At that moment, c has no value (and so is not a list that Part can work on). That leads to a cascade of follow on errors as the ReplaceAll is attempted with a broken rule. $\endgroup$
    – lericr
    Mar 23, 2022 at 14:46
  • $\begingroup$ For what it's worth, you could use RuleDelayed: spab[5, {{3, 4}, {7, 6}, 2}, 1] /. spab[a_, c_, b_] :> Plus[spa[a, #]*spbb[#, c[[2 ;;]], b] & /@ c[[1]]] $\endgroup$
    – lericr
    Mar 23, 2022 at 14:55
  • $\begingroup$ That indeed seems to get rid of the error, but then it doesn't perform the sum... $\endgroup$
    – Marcosko
    Mar 23, 2022 at 16:52
  • $\begingroup$ Right. I was showing that RuleDelayed holds the right side of the rule unevaluated. I still think your best bet is just defining DownValues. $\endgroup$
    – lericr
    Mar 23, 2022 at 17:02

1 Answer 1


Rather than try to do replacements, you could just define DownValues (transformation rules):

spab[a_Integer, b : {__Integer}, c_Integer] := 
  spa[a, First@b]*spbb[First@b, Rest@b, c];
spab[a_Integer, b : {_List, ___}, c_Integer] := 
  Dot[Thread[spa[a, First@b]], Thread[spbb[First@b, Rest@b, c], List, 1]]

I'm making assumptions about the arguments being Integers and so forth, which may need to be changed. If you don't want these transformations to be applied automatically, then define them for a different symbol (e.g. spabTransform) and then use ReplaceAll with spab->spabTransform.


I like this better. Fewer assumptions and removes duplicate arithmetic.

spab[a_, b : {_List, ___}, c_] := 
  Dot[Thread[spa[a, First@b]], Thread[spbb[First@b, Rest@b, c], List, 1]];
spab[a_, b : {__}, c_] := spab[a, MapAt[List, b, 1], c];
  • $\begingroup$ Could you briefly explain what the different commands are doing? Specifically, I would love some clarification on b : {_List, ___} and b : {__} $\endgroup$
    – Marcosko
    Mar 23, 2022 at 17:10
  • $\begingroup$ := is infix form of SetDelayed, so we're defining some transformation rules that will become DownValues for spab (you can evaluate DownValues[spab] to see how Mathematica will now transform spab-headed expressions). These DownValues, by the way, look a lot like what you would try to do with ReplaceAll rules, but since this functionality is already built into Mathematica, using ReplaceAll is kind of re-inventing the wheel here. ... $\endgroup$
    – lericr
    Mar 23, 2022 at 17:21
  • $\begingroup$ The left had side of these expressions is the pattern to match. You're already familiar with Blank (the underscore). There are other versions, specifically BlankSequence and BlankNullSequence. So, this bit {__} (using BlankSequence) is a pattern that will match a List that has at least one element. This bit {_List, ___} is a pattern that will match a List whose first element is a List and has zero or more elements following it (that's what BlankNullSequence is for). ... $\endgroup$
    – lericr
    Mar 23, 2022 at 17:25
  • $\begingroup$ The colon is just infix for Pattern. So, b : {__} is saying, here is a pattern that we'll name b and the pattern will match a list that has at least one element). Similarly, b : {_List, ___} is saying, here is a pattern that we'll name b and that will match a list that has a list in first position and zero or more elements following. $\endgroup$
    – lericr
    Mar 23, 2022 at 17:29
  • $\begingroup$ Thank you, that was a very insightful response :). I'll play around with it and see if I can define everything I have to do in this way. $\endgroup$
    – Marcosko
    Mar 23, 2022 at 17:44

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.