How to pass a list as function argument?

I have the following function

lFreqPhylo[a_, Q_, b_, p_] :=  Sum[Log[freqFunction[r[[p]][[i]], L[[p]][[i]], a, Q, b, {i, 1, nbranches[[p]]}];


The objects L, r and nbranches are simply lists of data, and the argument p tells the function which dataset to refer to.

I'd like to define a function which sums all of the datasets (here n=2) and uses a different argument a and b for each dataset, so to write it our by hand,

lFreqPhylo[a1, Q, b1, 1] + lFreqPhylo[a2, Q, b2, 2]


To this end, I defined two lists,

A = {a1,a2}


and

B = {b1,b2}


(This list has more elements but I'm giving the example of 2 elements to keep it simple.) What this means is that I'd need to pass the lists A, B and the index to each list (p in lFreqPhylo) to a new function lFreq. The following approach however failed:

lFreq[A__, B__, Q_] := Sum[lFreqPhylo[A[[p]], Q, B[[p]], p], {p, 1, 2}]; (*Doesn't work!*)


How can I pass the two lists, A and B, to the function lFreqPhylo such that I can (a) use the 'Sum[...]' expression on the right hand side, (b) use the list elements, a1, a2, b1 and b2, as arguments of the function?

• Kuba, Well, problem is I have two lists and need to pass an index of the list as an argument. So following your advice, having defined two lists, A = {a1,a2}; B = {b1,b2}; I did f1[a_, b_, Q_] := (a b)^2/Q; f2[Q_, a__, b__] := Total[MapThread[f1[#1, #2, Q] &, {A, B}]]; and now it works. But what if I have f1[a_, b_, Q_,i_] := (a b)^2/Q i where i is the index of the element of the list (1 or 2)? How do I define f2 then? Commented May 27, 2014 at 13:36
• You're absolutely right, I've now edited it. Commented May 27, 2014 at 14:09
• Change the LHS of your definition to lFreq[A_, B_, Q_] and it works as expected; no?
– kglr
Commented May 27, 2014 at 22:10

Edit

The definition you make

lFreq[A__, B__, Q_] := [...]


is not very nice. There is an ambiguity here and Mathematica will not know how many elements to match to A and how many to match to B. We can check this by defining

lFreqTest[A__,B__]:= {A}


Then

lFreqTest[1, 2, 3, 4]


gives

{1}


So that we see that Mathematica tries to make B__ as long as possible. There is a terrible way around this

Clear@tester
tester[PatternSequence[a__, b__] /; (Length@{a} == Length@{b})] := "ok"


which gives

tester[1,2]

"ok"

tester[1,2,3]

tester[1,2,3]


But this will be very slow. You should look to alternatives.

Original

A = {1, 2};
B = {2, 3};
Q = 6;


The actual functions

f1[a_, b_, Q_, i_] := (a b)^2/Q;

lFreq[listA_, listB_, Q_] :=

lFreq[listA_, listB_, Q_] :=
Total@
f1[#1, #2, Q, #3] &
,
{listA, listB, Range[Length@listA]}
]


Now we have

lFreq[A, B, Q]

20/3

• Jacob, I have now changed the original question such that it contains all the sub-questions I had. Sorry for the confusion. Commented May 27, 2014 at 14:10
• Thanks Jacob. I've written the following and it seems to work. Do you think this is better or do you think it will be slow too and should I find another way? lFreqPhylo[a_, Q_, b_, p_] := Sum[Log[freqFunction[r[[p]][[i]], L[[p]][[i]], a, Q, b]], {i, 1, nbranches[[p]]}]; lFreqPhylo2[listA_, listB_, Q_] := Total@MapThread[ lFreqPhylo[#1, Q, #2, #3] &, {listA, listB, Range[Length@listA]}]; lFreq[A_, B_, Q_] := Evaluate[lFreqPhylo2[A, B, Q]]; Commented May 27, 2014 at 15:26
• @Rafal that looks quite reasonable. Just so you know, you can write r[[p]][[i]] as r[[p, i]]. Furthermore your definition for lFreq may be a bit tricky. Either Q A and B are already set, and it is misleading to have them as function arguments. Or they are not set, and MapThread will probably fail. Maybe it works if you define this function before you define lFreqPhylo2, A, B and Q. Commented May 27, 2014 at 15:44
• Longest can help here. Commented May 27, 2014 at 16:49
• +1 for tester[PatternSequence[a__, b__] /; (Length@{a} == Length@{b})] := "ok" Commented Sep 21, 2016 at 1:44

lFreq[A_List, B_List, Q_]:=Sum[Function[i, lFreqPhylo[A[[i]], Q, B[[i]], i][j], {j, 1, 2}]

lFreqPhylo[a1, Q, b1, 1] + lFreqPhylo[a2, Q, b2, 2]