while fiddling about the 99 Lisp Problems (P46, e.g. [1]) I ran into a situation where I was able to implement a simple solution based on a macro while I am failing getting it done by a function. This gives me a bad feeling and I would love to have someone more experienced comment on my solution. Is it appropriate to use a macro here and why is a function-based solution not working here?

If I try to adopte my macro solution to the next problem (P47, e.g. [2]) I ran into trouble. I thought I could define a rather simple recursive function (swap-operators) which swaps the operators from infix to prefix notation. (Assuming that only valid three-elemente logical expression will occur. I have studied Pascal's solution [2] but it is way to complex for my level right now and I wanted to use only things which I completely understand.) If I use this function in combination with a macro (table2) I end up in a situation where the logical expression is not evaluated itself, i.e. my truth tables always prints true because there is something different from 'fail.

What would be the right way to combine my function manipulating the expression and the simple macros which was working before?

while fiddling about the 99 Lisp Problems (P46, e.g. [1]) I ran into a situation where I was able to implement a simple solution based on a macro while I am failing getting it done by a function. This gives me a bad feeling and I would love to have someone more experienced comment on my solution. Is it appropriate to use a macro here and why is a function-based solution not working here?

What you are trying to do can't be done by a function, unless you use EVAL or COMPILE. Your function TABLEF is wrong for two reasons:

It seems like the values of A and B in this function are supposed to be symbols. however, LOOP will bind the values of A and B, not of the symbols passed to the function. There is no way of changing the value of a symbol given at run-time unless it's a special symbol (declared with DEFVAR or DEFPARAMETER).

At the beggining, the value of A is 'X and the value of B is 'Y. When the macro LOOP is executed, the value of both A and B is T. What is the value of X and Y? None! X and Y don't have any values associated with them. And how can you give a value to X and Y in those circunstances? The only way would be to bind the value of the symbols with SYMBOL-VALUE or PROGV, but don't do that, that is not a good idea.

CL-USER> (defun test (a b) (format t "The value of A is ~S.~%" a) (format t "The value of B is ~S.~%" b) (loop :for a :in '(t t nil nil) :for b :in '(t nil t nil) :do (format t "Now, the value of A is ~S.~%" a) (format t "Now, the value of B is ~S.~%" b)))TESTCL-USER> (test 'x 'y)The value of A is X.The value of B is Y.Now, the value of A is T.Now, the value of B is T.Now, the value of A is T.Now, the value of B is NIL.Now, the value of A is NIL.Now, the value of B is T.Now, the value of A is NIL.Now, the value of B is NIL.NIL

Now, take a look at the lambda. What does this function return? It returns the value of the variable EXPRESSION - which, in our case, is the list '(and x y). In Lisp, there is no difference between data and code. This function returns the code, it doesn't evaluate the code.

CL-USER> (defun test2 (a b expression) (format t "The value of A is ~S.~%" a) (format t "The value of B is ~S.~%" b) (format t "The value of EXPRESSION is ~S.~%" expression) (loop :for a :in '(t t nil nil) :for b :in '(t nil t nil) :do (format t "Now, the value of A is ~S.~%" a) (format t "Now, the value of B is ~S.~%" b) (format t "Now, the value of EXPRESSION is ~S.~%" expression) (format t "The value returned by the lambda function is ~S.~%" (funcall (lambda (a b) expression) a b)))); in: DEFUN TEST2; (FUNCALL (LAMBDA (A B) EXPRESSION) A B); ==>; (SB-C::%FUNCALL (LAMBDA (A B) EXPRESSION) A B); ; caught STYLE-WARNING:; The variable A is defined but never used.; ; caught STYLE-WARNING:; The variable B is defined but never used.; ; compilation unit finished; caught 2 STYLE-WARNING conditionsTEST2CL-USER> (test2 'x 'y '(and x y))The value of A is X.The value of B is Y.The value of EXPRESSION is (AND X Y).Now, the value of A is T.Now, the value of B is T.Now, the value of EXPRESSION is (AND X Y).The value returned by the lambda function is (AND X Y).Now, the value of A is T.Now, the value of B is NIL.Now, the value of EXPRESSION is (AND X Y).The value returned by the lambda function is (AND X Y).Now, the value of A is NIL.Now, the value of B is T.Now, the value of EXPRESSION is (AND X Y).The value returned by the lambda function is (AND X Y).Now, the value of A is NIL.Now, the value of B is NIL.Now, the value of EXPRESSION is (AND X Y).The value returned by the lambda function is (AND X Y).NIL

Pay attention to the STYLE-WARNING, telling you that (lambda (a b) expression) doesn't use the value of A or B. Also, see how the value that the lambda function returns is the same value of the variable EXPRESSION.

You basically ran into the same problem in the second example by defining TABLE2F as a function.

thanks for your reply and the examples you gave. This was exactly what was driving me to implement table as a macro in the first place. I just got confused when I wasn't able to extend it using the function swap-operators. As I said in a next step i wanted to implement a way to deal with more natural notation for the logical expression (Although I am getting totally used to the prefix notation already), e.g. (A and B) instead of (and A B). I thought for this limited case a simple function which manipulates the expression should be sufficient, e.g. something like this as a first approximation (table is the macro working fine itself):

But it ends as as can been seen in a problem, leading to "True" in all cases. I think I understand that this is because the macro table is expanded before the function swap-operators is evaluated. The first macro expansion leads to

I guess, again the actual logical expression is not evaluated at run-time. Because swap-operators is supposed to work recursively on nested expressions I hesitated to implement it as a macro. But maybe this is the solution here?

I think the better way to implement this is to use EVAL like the first version of the function TABLE in P46. And, yes, I think this is a legitimate use of EVAL, because what you want is to evaluate expressions and see the result of the evaluation.

Okay, I have looked once more at Pascal's solution and do understand now how to implement it as a pure function. Although, I find my macro solution nice because of its brevity. Nevertheless, I would love to understand how one could combine the function swap-operators with the macro table.