Re: Loop problem

From: Alan Crowe (alan_at_cawtech.freeserve.co.uk)
Date: 07/22/04


Date: 22 Jul 2004 18:05:37 +0100

I made some guesses.

1) You want to use the built in AND and OR on a formula you
   type in interactively. For example:

   * (eval (read))
   (and (or nil t) t)

   T

   or adding a bit of polish

   * (eval (progn
          (format t "~&Enter a boolean formula: ")
          (finish-output)
          (read)))

   Enter a boolean formula: (and t (not nil))

   T

   That is attractive because you use the AND and OR in the
   language already, instead of writing your own interpreter
   to interpret the formula.

2) You don't actually want to type in T and NIL
   yourself. You are more interested in printing out a truth
   table. Something like:

   * (let ((both '(nil t)))
        (dolist (a both)
          (dolist (b both)
            (dolist (c both)
              (format t "~&~4A~4A~4A -> ~A" a b c (and a (or b c)))))))

          NIL NIL NIL -> NIL
          NIL NIL T -> NIL
          NIL T NIL -> NIL
          NIL T T -> NIL
          T NIL NIL -> NIL
          T NIL T -> T
          T T NIL -> T
          T T T -> T

That leaves two problems. 1)EVAL doesn't see lexical
variables. 2)coding gets tedious

(let ((form '(and a b))
        (a t)
        (b t))
    (eval form))

only gets half way. FORM is accessed to obtain (and a b)
which is passed to EVAL.

EVAL then tries to evaluate (and a b) but cannot see A and
B.

One solution is

(defvar a)
(defvar b)
(let ((form '(and a b))
      (a t)
      (b t))
  (eval form))
T

but the defvars haven't just made the bindings dynamic, they
have made the symbols dynamic. Every binding for A and B
until you quit the image is going to be dynamic, even inner
ones that you think are lexical.

So, quitting the image and restarting (to undo the effect of
the defvar's),

* (let ((form '(and a b))
        (a t)
        (b t))
    (declare (special a b))
    (eval form))

Warning: These variables are undefined:
  A B

=> T

Now we've got a plan - tabulate the function we type in at
run time with a nest of dolists complete with special
declarations to pass the variables on to eval.

(let ((form (read)))
  (dolist (a '(nil t))
    (declare (special a))
    (dolist (b '(nil t))
      (declare (special b))
        etc etc this gets real old, real quick.
          (format ... (eval form))

Guess number three - you want plenty of variables, so you
will need a macro to type in the nest of dolists for you.

Well, in one rather peculiar way, macros are easier to write
than functions. Functions have to go all the way and finish
the job they start. Macroexpansions are resubmitted to the
macroexpander for further expanion. That is crucial. When you
write a macro that expands to something built-in to CL, that built-in
may itself be implemented as a macro. So if macros weren't
resubmitted everything would break horribly.

The surprising result of this is that macros don't have to
go all the way. They merely have to make progress.

A note on the name: DO-BITS is an OK name, but it suggests
to me 0 and 1, so I went for DO-LOG(ical)-BITS to suggest
nil and t. Also half the point of the macro is to make the
loop variables dynamic, so I put DYN at the front.

We want (dyn-do-log-bits (a b c .... x y z) code) to expand
to a nest of 26 DO-LISTs. One way is to write a macro that
actually builds that nest. I'm happy merely to make progress

(dyn-do-log-bits (a b c ... x y z) code) expands to

(dolist (a '(nil t))
  (declare (special a))
  (dyn-do-log-bits (b c d ... x y z) code))

The macroexpander will say "Oh I'm not finished yet." and
expand (dyn-do-log-bits ...) again

(dolist (a '(nil t))
  (declare (special a))
  (dolist (b '(nil t))
    (declare (special a))
    (dyn-do-log-bits (c d e ... x y z) code))

The macroexpander will say "Oh I'm not finished yet." and
expand (dyn-do-log-bits ...) again (and not get bored!)

All we need to be careful of is that

(dyn-do-log-bits () code)

expands to (progn code) or the macroexpander will never stop.

Take a look at

* (pprint (macroexpand-1 '(dyn-do-log-bits (a b c) code)))

(DOLIST (A '(NIL T)) (DECLARE (SPECIAL A)) (DYN-DO-LOG-BITS (B C) CODE))

which show the first step of macroexpansion.

Then look at

* (pprint (macroexpand '(dyn-do-log-bits (a b c) code)))

which shows what I said about built-ins being macros

finally, CMUCL offers

(pprint (walker:macroexpand-all '(dyn-do-log-bits (a b c) code)))

which produces lots of output, which you might want to leave
for later.

Today's guess is that you actually wanted a backtracking
search. It would look at (and (or a b)(not a))
First it would say,
"I'd better make the OR true, I'll set A=1"
next it would say
"I need the NOT to be true too"
"I need A=0"
"Merde! back to look at that OR again"
"B=1"
"A=0"
"Yeehaa!"

I've had a look at coding this,
http://alan.crowe.name/lisp/sat.txt but only got as far as a
greedy search for a solution, which is pretty useless
really. This problem is real computer science. It is hard,
much harder than playing about writing fill-the-template
macros. Good luck.

Alan Crowe
Edinburgh
Scotland



Relevant Pages

  • Re: Declaring Objects
    ... What this is saying is set the Colors variable to refer to the Colors sheet, ... > that I need to declare my objects and know that I would prefer to declare ... > Below is my first attempt to writing a macro, ... > Sub FindAndReplace() ...
    (microsoft.public.excel.programming)
  • Re: Converting C to Delphi
    ... macro and a million constants. ... Can this be imported into delphi or do I ... > Perform those calculations yourself and declare the constants with the ... One is temp, ...
    (alt.comp.lang.borland-delphi)
  • Re: VBA Word 2003 File Close
    ... It would be better to declare a variable as a Document and set that variable to the document that you are opening rather than rely on the active document. ... In a Word 2003 template document I have a macro triggered by a CheckBox ... document and then is supposed to close that second document. ... I get a run-time error 4198 "Command Failed" at the line that ...
    (microsoft.public.word.vba.general)
  • Re: one simple question
    ... You'll most likely find a macro called NULL in one of the Visual C++ ... this doesn't declare a function. ... Empty brackets would be equivalent to replacing the "null" with "void", ... also making this a function declaration. ...
    (comp.lang.cpp)

Loading