The first time, only hello shows up in the log. The second time we get all of hello=world. So since the \drs... bit in the list has an = in it, it needs to be protected.

At first sight, you would seem to be doing this already since you pass {\drs[lambda={x}]{Bar}} as one of the terms in the list. But a little more experimenting shows that the /.list iterator strips off all grouping so what actually gets passed is \drs[lambda={x}]{Bar} whence the call is:

\pgfkeys{/drs/lambda/.append = (\drs[lambda={x}]{Bar})

which triggers the error. The immediate solution is to put the braces in the list/.code code:

list/.code = {\pgfkeys{/drs/lambda/.append = {(#1)}}}

Testing the value of /drs/lambda shows that it now gets the right thing.

However, fixing that reveals a minor issue with the routine that you have! Because of the order of expansion, the inner \drs is executed after the outer one and so it sees (a)(b)(\drs[lambda={x}]{Bar}) as the initial value of /drs/lambda, to which it adds an \{(x)\} and prints out the full value again: (a)(b)(\drs[lambda={x}]{Bar})\{(x)\}. Which contains another call to \drs. And so on. And so on.

You could try to reverse the order of expansion by fully expanding the argument to the list, #1, before appending it, but I ran in to troubles with that (which I don't fully understand, but seem to be to do with how LaTeX handles commands with optional arguments). An alternative is to blank /drs/lambda with each call to drs since by the time the inner call is executed, the outer call has done its job and is no longer needed. There are a couple of (equivalent) ways to do this. For example,

(which rather defeats the object of the default argument so that could be removed.)

With those two modifications, I get:

{(a)(b)({(x)})}

for output.

Update: (to answer the updated question). The second problem is also about grouping (not expansion). When the .list is called, it sees:

\drs [presupposition={m},lambda={a}]{}

As far as it is concerned, that comma is fair game. The pseudo-grouping defined by the square brackets is ignored as it isn't a real grouping. So it splits this up as \drs[presupposition={m} and lambda={a}]{}. This messes up the following.

Fixing this depends on what else you are trying to achieve with these macros, what other kinds of inputs you wanted to be able to process. The simplest fix of all is simply to make the macro \drs have two mandatory arguments rather than one optional and one mandatory. This would ensure that the arguments to the inner call of \drs are protected and not split apart by the outer call. An alternative would be to use key-value pairs in the argument to \drs thus having a single argument which is a list which is then processed by \pgfkeys.

Thanks, I guess I still do not understand how optional arguments are handles exactly. The solution I came up with is to write a wrapper macro with an optional argument and call the real macro from it passing {} as a first argument if the optional argument is empty.
–
Nickolay KolevJun 26 '11 at 8:40

@Nickolay: The thing to remember about LaTeX's optional argument syntax is that there is no actual grouping involved. So in \test[a]{b} then the b is inside a group but the a is not. Thus the a might get messed with by something else (as in your situation) but the b is (mildly) protected. If you can pinpoint what you don't understand, ask a question about it - that's how I've learned about this sort of stuff.
–
Loop SpaceJun 26 '11 at 17:51