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?
Any comment is appreciated
Martin
In detail:
Code: Select all
(defmacro table (a b expression)
"Prints the truth table of a given logical expression in two variables."
`(loop :for ,a :in '(t t nil nil)
:for ,b :in '(t nil t nil)
:do (format t "~{~:[Fail~;True~]~^~T~}~%"
;; A bit awkward but I wanted to use True/Fail instead of
;; Lisp's t/nil but also wanted to use format's iteration
;; and conditional printing feature.
(list ,a ,b (unless (equal ,expression 'fail) t)))))
(defun tablef (a b expression)
"Prints the truth table of a given logical expression in two variables."
(loop :for a :in '(t t nil nil)
:for b :in '(t nil t nil)
:do (format t "~A~%";;"~{~:[Fail~;True~]~^~T~}~%"
;; A bit awkward but I wanted to use True/Fail instead of
;; Lisp's t/nil but also wanted to use format's iteration
;; and conditional printing feature.
(list a b (funcall (lambda (a b) expression) a b)))))
Code: Select all
(defun and/2 (a b)
"A predicate which returns 'true if both arguments are non-nil."
(cond ((and a b) 'true)
(t 'fail)))
Code: Select all
(defun swap-operators (expression)
"A simple function manipulating the order of operator and parameter in simple
logical expression. (A opr B) --> (opr A B) It is designed to walk down a
nested listed structure consisting of three-element list."
(if (and (listp expression) (= (length expression) 3))
;;; We are only dealing with valid logical expressions and will not signal any error.
(let ((first-element (first expression)) (second-element (second expression))
(third-element (third expression)))
(cond ((atom first-element)
(list second-element first-element (swap-operators third-element)))
(t (list second-element (swap-operators first-element)
(swap-operators third-element)))))
expression))
(defun table2f (a b expression)
"Prints the truth table of a given logical expression in two variables."
(table a b (swap-operators expression)))
[2] http://www.informatimago.com/develop/lisp/l99/p47.lisp