Re: eval in bash vs macro in lisp




Weiguang Shi wrote:
In article <m28xlccaz8.fsf@xxxxxxxxxxxxxxxxx>, Ari Johnson wrote:
Weiguang Shi <wgshi@xxxxxxxxxxxxxxxxxxxxx> writes:

Thank you! I could only suspect.

So although I don't understand LISP macros, I can still grok it.

Off-topic note: The verb "to grok" comes from Heinlein's fascinating
novel _A Stranger in a Strange Land_, and roughly means to have such
an intimate understanding of as to be nearly one with it. If you
don't understand something, you cannot grok it.
I understand what the word means. I meant it and don't think that's
impossible. But that's off-topic.


But back to the topic itself, macros can't be fairly analogized to any
other language that I know of, because they allow you to add syntactic
features to the language. I try explaining this by implementing a
'for' loop in Common Lisp using a macro. Common Lisp does not have
such a feature, so adding it with a macro is a substantial change to
the syntax of the language.

In C, you write:
for (i = 0; i < 10; i++) {
printf("i = %d\n", i);
}

In Lisp, this would look like:
(for (i 0) (< i 10) (incf i)
(format t "i = ~D~%" i))

If you type that into your Lisp, you will get an error or two. Those
errors will include the fact that there's no such function I and the
fact that there's no such function FOR.

Let's add it to the language:

(defmacro for (init continue next &body body)
(unless (consp init)
(error "Syntax error - init form must be a list"))
(let ((looplabel (gensym))
(var (first init))
(initval (second init)))
(unless (symbolp var)
(error "Syntax error - variable must be a symbol"))
`(prog ((,var ,initval))
,looplabel
,@body
,next
(when ,continue
(go ,looplabel)))))

Now try that example form again, and it will print out what you'd
expect. Lisp did not have this syntax beforehand and it does now.
You can't do that in bash.

One can certainly create a function with a name and parameter
sequence, call it ``new'' syntax, and inside the function evaluate
them into a sequence meaningful in the original bash syntax. After
all, they (the ``new'' syntaxes) are just functions, either in lisp or
bash, are they not? I completely fail to see how macro excels here.

No. In Lisp, compound forms (i.e. forms which are lists as opposed to
atoms like X, 42 or "abc") come in three flavors: special forms
(essentially, built-in syntax with evaluation rules specific to that
syntax), function call forms (with a uniform evaluation syntax that
applies to all functions) and macros. Macros look like special forms;
i.e. they are the way by which new user-defined syntax can be
introduced which looks indistinguishable from some special form.

The POSIX shell command language has "special forms" also, for instance

case expr in
pattern ) ... ;;
pattern ) ... ;;
* ) ... ;;
esac

for x in words
do
command
command
...
done

If the POSIX language was programmable, you would be able to write your
own forms like this.

Note that "for" cannot be written as a bash function, because the
function has no way to inspect what follows the for clause. You have to
be able to hunt down the "do" and the "done". If for were a function
in the above example, it would be given the arguments "x" "in" and
"words". It would then return, and the shell would then consider "do"
to be the next command. (Maybe you could hack something together using
separate functions. The "for" function could record something on a
hidden stack-like structure, and the "do" and "done" commands could
arrange for looping somehow. No idea how "done" would handle the
backward branch to the "do").

A macro in Lisp is a code-transforming function that is running inside
the Lisp interpreter or compiler to implement a new syntactic
recognizer. The macro is identified by the symbol in the first position
of the list form. The entire form is then handed off to the
corresponding function, which produces some other form that is then
subsituted in place of that form. The macro call happens at the time
the source code is processed, not when it is evaluated. In some modes,
the two may be close together, such as in interactive evaluation of
forms from a listener. The programmer types in a macro calling
expression, the macro function is called to expand it, and right after
that, the results of macroexpansion are evaluated. But in general, the
two processes need not even take place in the same image.
Macro-expansion can be done on a build machine, and evaluation of the
results on the target machine.

The shell language is sometimes used with a macro processor, but an
external one. For instance, the GNU Autoconf system uses the m4 macro
expander to generate scripts and makefiles. A "configure.in" written in
the macro language is converted to "configure" which is a shell script.
The output of the macro expander is raw text which has to be tokenized,
because the shell doesn't have a data-structure based language that
could be targetted by an integrated macro processor.

.



Relevant Pages

  • Re: Programming By The Seat Of Your Pants
    ... the only way I'm going to learn Lisp ... was Python, a better scripting language. ... Not much in the way of libraries. ... then add a macro layer that allows you to write things the way you want to ...
    (comp.lang.lisp)
  • Re: Macro Question: Paraphrasing
    ... Instead, you will need to put some macro around all the forms that need to be processed, and use a code walker to process each subform, a la ... The programming language has its own grammar rules that are simpler and much more consistent than natural language. ... Far from enforcing English grammar rules on Lisp, these ideas entail adding context to arbitrary ordering and paraphrasing awkward expressions. ... The variable clauses resemble dependent clauses, and the main clause represents the independent clause. ...
    (comp.lang.lisp)
  • Re: A "killer" macro
    ... could be included as a feature in another language, ... The "killer" macro, in CL ... of the functional features of Lisp. ... When confronted by fellow programmers with the question "so why is ...
    (comp.lang.lisp)
  • Re: What you can do with macros in Lisp
    ... > Imagine you have a language with a CASE expression. ... > equivalent to writing a macro system...) ... as explained in Paul Graham's "On Lisp" in his extended coverage ... macro calls by function calls encapsulating the bodies in closure ...
    (comp.lang.lisp)
  • Re: Three questions
    ... of the functionality you are doing here already exists in lisp. ... Another way to implement this macro, ... really understand all of the binding forms in Common Lisp and also make ... often KEY for properly implementing control structures. ...
    (comp.lang.lisp)