Explanation of macros; Haskell macros

K

Kenny Tilton

Jesse said:
The existence of Template Haskell indicates to me that there are things
people want to do with macros that aren't reasonably done in Haskell. I
don't even know if I've ever wanted to do these things, because people
rarely miss language features that they don't know.

A language feature is not worth having unless it meets a need which
exists independent of anyone thinking to create said language feature.
If you follow links below and poke around the Cliki you can locate those
folks who got to Lisp via the Greenspun route in some way shape or form,
people who were trying to do Lisp, not knowing there was such a thing.

I once had a contract to develop a browser app that was going to have
about twenty screens. They would all work the same, but on different
views of the DB. COBOL does not have macros, but I sure as hell wasn't
going to write one and clone it eighteen times.

COBOL /does/ have COPY REPLACING. They may not have intended for someone
to copy an entire program splicing in different form names and RDB view
names, but where there is a lazy programmer...

:)

kenny


--
http://tilton-technology.com

Why Lisp? http://alu.cliki.net/RtL Highlight Film

Your Project Here! http://alu.cliki.net/Industry Application
 
C

Coby Beck

Olaf Klischat said:
Just for the record: Is the "append" stuff necessary? Why not write
this as

(defmacro econd (&body body)
`(cond ,@body
(t (error (format nil "fell through ECOND form. could not satisfy any of the following: ~{~%~A~}~%"
',(mapcar #'(lambda (cond)
(car cond))
body))))))

That works. I blame Pascal for my gratuitous use of append and now I have
been exposed as one of those copy-paste-alter code monkeys without a formal
correctness proof in my head ;)
 
K

Kenny Tilton

Peter said:
Well, of those the debugger interaction is perhaps the most serious.
Yet in practice (Hey Pascal, I almost said "in 99% of cases"!) it
doesn't seem to be that much of a problem. Maybe that's because we've
just learned to deal with the pain; maybe MACROEXPAND is all you
really need to get your bearings. At any rate, there's no in principle
that a Lisp implementation couldn't keep track of macro information
along with the compiled code just the way most compiler keep track of
line number information in order to show you the code as written in
the debugger. (And if it was really slick to let you step through the
macro expansion, etc.)

Cue Duane of Franz. He mentioned over lunch at ILC2003 where John
McCarthy used my laptop for ten minutes that their Allegro Common Lisp
product was going to exactly that, including the expansion thing. I
think he also said something about expanding in steps, but I did not
quite follow. I suppose it is like stepping into a function or not,
except the question here is whether nested macros get expanded (and you
then get to step through those).

kenny

--
http://tilton-technology.com

Why Lisp? http://alu.cliki.net/RtL Highlight Film

Your Project Here! http://alu.cliki.net/Industry Application
 
D

Duane Rettig

Kenny Tilton said:
Cue Duane of Franz. He mentioned over lunch at ILC2003 where John
McCarthy used my laptop for ten minutes that their Allegro Common Lisp
product was going to exactly that, including the expansion thing. I
think he also said something about expanding in steps, but I did not
quite follow. I suppose it is like stepping into a function or not,
except the question here is whether nested macros get expanded (and
you then get to step through those).

Well, yes, but not for another release or so - I've got to get
environments access working right first (where do you think all
of this info and capability will be coming from? :)

It is indeed true that macros tend to be opaque, and experience
with the best of C/C++ debuggers and those of other lanuages with
macro systems will simply reinforce this fact. However, Common Lisp
macros tend not to be opaque (it is one of the more useful parts of
the fact that CL macros work on the same data that programs work on),
and one can see what a macro doing by simply macroexpanding it - for
example, try (pprint (macroexpand '(dotimes (i 10) (print i)))) in
a CL listener. With this much openness, it doesn't seem unreasonable
to expect a debugger to be able to use such information to make macros
and the forms they expand into completely debuggable and steppable at
any desired level.
 
M

Marcin 'Qrczak' Kowalczyk

With this much openness, it doesn't seem unreasonable
to expect a debugger to be able to use such information to make macros
and the forms they expand into completely debuggable and steppable at
any desired level.

Does any debugger do this?
 
P

Pascal Bourguignon

Kenny Tilton said:
Cue Duane of Franz. He mentioned over lunch at ILC2003 where John
McCarthy used my laptop for ten minutes that their Allegro Common Lisp

Just put "John McCarthy used my laptop for ten minutes" in your
signature and forget it! :)
 
J

james anderson

Marcin said:
Does any debugger do this?

? you mean like this? wrt evaluating

(defun testf (x)
(dotimes (i x)
(print i)))

(step (testf 2))

==>

(testf 2)
(block testf (dotimes (i x) (print i)))
(dotimes (i x) (print i))
x = 2
(block nil (if (ccl::int>0-p #:g25) (tagbody #:g24 (print i) (locally #
#) (unless # #))) nil)
(if (ccl::int>0-p #:g25) (tagbody #:g24 (print i) (locally (declare #)
(setq i #)) (unless (eql i #:g25) (go #:g24))))
(ccl::int>0-p #:g25)
#:g25 = 2
t
(tagbody #:g24 (print i) (locally (declare (ccl::settable i)) (setq
i (1+ i))) (unless (eql i #:g25) (go #:g24)))
(print i)
i = 0
0
(locally (declare (ccl::settable i)) (setq i (1+ i)))
(setq i (1+ i))
(1+ i)
i = 0
1
1
1
(unless (eql i #:g25) (go #:g24))
(not (eql i #:g25))
(eql i #:g25)
i = 1
#:g25 = 2
nil
t
(progn (go #:g24))
(go #:g24)
(print i)
i = 1
1
(locally (declare (ccl::settable i)) (setq i (1+ i)))
(setq i (1+ i))
(1+ i)
i = 1
2
2
2
(unless (eql i #:g25) (go #:g24))
(not (eql i #:g25))
(eql i #:g25)
i = 2
#:g25 = 2
t
nil
nil
nil
nil
nil
nil
nil
nil


v/s

(testf 2)
(block testf (dotimes (i x) (print i)))
(dotimes (i x) (print i))
nil
nil
nil


depending on whether one stepped into or over the macro form?
 
D

Duane Rettig

Marcin 'Qrczak' Kowalczyk said:
Does any debugger do this?

Most Lisp debuggers will do this with compiled code. I know of nne which
do this to compiled code without recompilation.

I apologize for the lack of context in my reply - it was late last night
and I have no time this morning as well; Lisp, and in particular CL, does
very well in debugging interpreted code. However, just as I detest the
need for a -g option in gcc, I always strive to avoid requiring the
user to recompile in order to get debugging info. In CL, the debug
quality interacts with but is separate from the speed, safety,
compilation-speed, and space qualities.
 
D

Duane Rettig

james anderson said:
? you mean like this? wrt evaluating

(defun testf (x)
(dotimes (i x)
(print i)))

(step (testf 2))

I've reproduced the whole code below so that readers can see it
when they contemplate this comment and a question (I have no time
now, but I'll explain tonight if nobody gets it, although it should
be easy): James did not say what lisp he was using, but presumably
it is a Common Lisp. The following example was obviously not
compiled. Can you explain why?
 
J

james anderson

Duane said:
I've reproduced the whole code below so that readers can see it
when they contemplate this comment and a question (I have no time
now, but I'll explain tonight if nobody gets it, although it should
be easy): James did not say what lisp he was using, but presumably
it is a Common Lisp. The following example was obviously not
compiled. Can you explain why?

yes. whereby the first transcript is the result of successive "steps into".

....
 
P

prunesquallor

Duane Rettig said:
Most Lisp debuggers will do this with compiled code. I know of none which
do this to compiled code without recompilation.

MIT Scheme (which we all know is not Common Lisp) keeps around enough
debug information to determine the source code being executed at each
step in the compiled code. I don't recall if there is a compiled code
stepper per se, but crawling down the stack in compiled code shows the
source code that was being evaluated.
 
J

Jesse Tov

Kenny Tilton said:
A language feature is not worth having unless it meets a need which
exists independent of anyone thinking to create said language feature.

Obviously--but that doesn't mean that what those features should look
like is obvious, or even that people always know that difficulties
they're having can be solved by a language feature. Sometimes you don't
know you have a problem until you see the solution, but that doesn't
mean you didn't have the problem in the first place.
If you follow links below and poke around the Cliki you can locate those
folks who got to Lisp via the Greenspun route in some way shape or form,
people who were trying to do Lisp, not knowing there was such a thing.

I was wondering who this Greenspun y'all seem to worship is, so I did a
Google search. His list "nice languages" is "Haskell, ML, and Lisp". I
doubt anyone is "trying to do Lisp" in Haskell.

Jesse
 
F

Fergus Henderson

MIT Scheme (which we all know is not Common Lisp) keeps around enough
debug information to determine the source code being executed at each
step in the compiled code. I don't recall if there is a compiled code
stepper per se, but crawling down the stack in compiled code shows the
source code that was being evaluated.

Including macros invocations?

When you say "source code", do you really mean source code, or do
you mean the results of macro-expansion?

If I have a function foo whose body invokes a macro bar which calls a
function baz, can I get a "stack trace" or equivalent which shows me the
line in the definition of bar which invokes baz, and the line in the
definition of foo which invokes bar? Can I see the bindings of the
parameters of bar?

(It would be great if I could, and there's no serious practical obstacle
AFAIK, but I don't know of any debuggers that actually do that.)
 
J

Joachim Durchholz

Peter said:
Hmmmm. The special forms (25 of them, called special operators these
days, by the by) are used the same in macros and functions. Lisp's
customizable reader is a separate thing--there is no need to customize
the reader to write macros.

You're right, and made me rethink what's actually disturbing me about
macros.

Perhaps it's that I have to adapt to dual-mode (two-tier?) thinking: I
have to reason about both what the macros are doing and what the
software is doing.
Alternatively, I could consider the macros as "part of the language" and
not reason about the macro code but about their effects - in which case
I have effectively augmented the language by all macros that are in use.

Personally, I'd still prefer a compiler that's evaluating constant
expression.

Is there anything that a macro does that can't be done by preevaluating
data structures that contain functions (or closures)? At first glance,
I'd say no, but then I don't know what macros are used for in practice.

Um, well, yes, there is one thing that macros can do: extending syntax
in ways that aren't part of the original language syntax. E.g. replacing
all those parentheses by indentation, or something similar un-Lispish.
(Extending syntax in such ways is a mistake IMHO, but YMMV. Anyway, I'm
more interested in the question if there's any /semantics/ that can be
done via macros but not via compile-time evaluation.)
I'm not sure what "extra" forms you're talking about. Other than
DEFMACRO, I guess. But by that argument we'd be better off without
DEFUN too because that's just another darn thing to learn.

I believe it's not DEFMACRO that's complicating things, it's the macros
that it allows (see above).
Interesting. A lot of people suspect that who haven't actually used
Common Lisp macros. Yet almost all Common Lispers--who by in large are
*not* monolinguists--think macros are one of Common Lisp's great
features. I'm not saying your wrong, but if those better solutions are
out there for all the things I can do with macros, I haven't seen
them. Now I don't know Haskell or ML so I'm also suffering from finite
knowledge. Maybe one day I'll have time to learn one of them for
myself and see if they really do offer better solutions.

Agreed on all accounts (except that I don't know how "multilingual"
Lispers really are *g*).

Does anybody have a keyword-style list of useful applications of the
macro facilities?
Well, of those the debugger interaction is perhaps the most serious.
Yet in practice (Hey Pascal, I almost said "in 99% of cases"!)

"99% of all cases" is a pretty good argument actually :)
It's just that Pascal doesn't (want to) believe that it's enough for
type checking. His problem, not mine...
> it
doesn't seem to be that much of a problem. Maybe that's because we've
just learned to deal with the pain; maybe MACROEXPAND is all you
really need to get your bearings. At any rate, there's no in principle
that a Lisp implementation couldn't keep track of macro information
along with the compiled code just the way most compiler keep track of
line number information in order to show you the code as written in
the debugger. (And if it was really slick to let you step through the
macro expansion, etc.)

Agreed.
I'm getting more and more convinced that it's not language size or KISS
issues that's setting me off, it's that "two-tier thinking" that I
(perhaps mistakenly?) associate with macros.
Clearly. I find Common Lisp to be a pretty beautiful piece of
*engineering*. Which may be different than a beautiful realization of
a beautiful theory.

I wouldn't want HM typing if it were just beautiful theory.
HM typing happens to be a beautiful theory. Things are getting less
beautiful once you interact with the Real World (TM), which is stateful
- OTOH, Real World is a mess, so don't expect computing to be beautiful
anymore when there is interaction with it *g*. What surprised me is how
much of a computation can be separated from such interaction. With the
proper framework, one can even describe interaction patterns (which are
themselves stateless), feed these patterns to the framework, and watch
in amazement how the execution engine follows these patterns. It's the
kind of abstractive facility I've been yearning for decades...
Lisp could do this just as well. It's just not done because taking the
shortcut and doing stateful computations directly is so much easier.
(And I don't pretend that functional languages are doing this kind of
thing perfectly right now. I think the potential in these ideas is just
beginning to be exploited - and what's available is already quite
impressive.)
Well, if I promise to continue to think that someday I really should
learn a hard-core FP language so I can see what all the static typing
fuss is about, will you promise to think in the back of your mind that
maybe someday you should learn Common Lisp and see what makes us all
so gaga over macros.

Actually I'm trying to understand macros and macro usage right now,
without having to learn all the details of CL (which would be a bit of
overkill - I know it might not be enough, but then my time is limited so
I'm doing my best within the available budget).

Regards,
Jo
 
P

Pascal Costanza

Joachim said:
Is there anything that a macro does that can't be done by preevaluating
data structures that contain functions (or closures)? At first glance,
I'd say no, but then I don't know what macros are used for in practice.

Macros are mainly used for abstracting away details of sophisticated
protocols. For me, the "Hello, World" of macro programming is this:

When you want to bind to a resource, you usually have to make sure that
you also unbind again later on. The standard pattern in many languages,
modulo syntactic variations, is this:

try: bind resource
do something
finally: unbind resource


The fact that you need to place the unbind in a finally statement
reflects the requirement a protocol imposes on the use of rources: You
have to make sure to execute the necessay steps in a certain order, and
you have to make sure that certain steps are always executed, no matter
what. There are lots of examples like this in programming, and
especially more complicated ones.

A macro allows you to abstract away from this. The same code, in a
language with macro support, would look like this:

with-bound-resorce:
do something

The macro "with-bound-resource" takes care of executing the right steps
at the right time.

Now, this is admittedly not an example for a particularly sophisticated
protocol. Therefore, one of the usual gut reactions from people who are
not used to macros yet is "but I can do this with higher order functions!"

However, what this example already shows is: The with-bound-resource
macro doesn't tell you anything about how it achieves its goals. Yes,
the natural way to implement this example is with a HOF, but you could
also use a completely different approach. _With macros you can build
abstractions that completely hide their implementation details._

This becomes especially useful as soon as your protocols become more
sophisticated, and you need to insert instructions at arbitrary places
in the code being passed to a macro, or need to control evaluation of
the code being passed in some other details.

Because of this high level of expressive power that macros provide,
Common Lispers use them regularly even for simple things. You can
effectively write domain-specific abstractions that don't leak, and
therefore it is justified to use them even for simple protocols.
Um, well, yes, there is one thing that macros can do: extending syntax
in ways that aren't part of the original language syntax. E.g. replacing
all those parentheses by indentation, or something similar un-Lispish.
(Extending syntax in such ways is a mistake IMHO, but YMMV. Anyway, I'm
more interested in the question if there's any /semantics/ that can be
done via macros but not via compile-time evaluation.)

Compile-time evaluation is a red herring. Macros do their job by
rewriting abstract syntax trees. (Lisp and macros go very well together
because in Lisp, you essentially program using a notation that maps
directly to an internal syntax tree, nearly without any parsing overhead.)

Since the syntax tree is usually available at compile time, that's the
natural time to let macros do their job. However, in theory it wouldn't
be a problem to use macro expansion at runtime.

(In Common Lisp, this is already possible in limited ways: an
interpreted implementation of Common Lisp expands macros during
evaluation, and when you call EVAL or COMPILE, macros are also expanded
at runtime. However, you cannot pass macros around as first-class
objects and APPLY them, at least not in the same way as functions. If
you wanted to do that the language implementation would need to keep the
lexical environment information available at runtime.)
Does anybody have a keyword-style list of useful applications of the
macro facilities?

Do you have a keyword-style list of useful applications of functions?


Pascal
 
J

Joachim Durchholz

Pascal said:
When you want to bind to a resource, you usually have to make sure that
you also unbind again later on. The standard pattern in many languages,
modulo syntactic variations, is this:

try: bind resource
do something
finally: unbind resource

[...]

Now, this is admittedly not an example for a particularly sophisticated
protocol. Therefore, one of the usual gut reactions from people who are
not used to macros yet is "but I can do this with higher order functions!"
Indeed.

However, what this example already shows is: The with-bound-resource
macro doesn't tell you anything about how it achieves its goals. Yes,
the natural way to implement this example is with a HOF, but you could
also use a completely different approach. _With macros you can build
abstractions that completely hide their implementation details._

I can completely hide implementation details with HOFs, too. At least
for my personal definition of "completely" - macros might have a
different idea of that.
This becomes especially useful as soon as your protocols become more
sophisticated, and you need to insert instructions at arbitrary places
in the code being passed to a macro, or need to control evaluation of
the code being passed in some other details.

Inserting "at arbitrary places" seems rather unmodular to me.
Either the macro would have to know about the code that it's being used
in, so that it can identify the places where to insert the code.
Or the code using the macro will have to pass information to the macro -
which, in a HOF context, means that the code using the HOF approach will
have to pass the code for "before the insertion point" and "after the
insertion point" as separate parameters, and the HOF would do the
necessary linkage between the two codes.
I'm not sure that macros offer a significant gain here.
Because of this high level of expressive power that macros provide,
Common Lispers use them regularly even for simple things. You can
effectively write domain-specific abstractions that don't leak, and
therefore it is justified to use them even for simple protocols.

OK, but the same can be said for HOFs.
The question is: in what ways are macros superior to HOFs to accomplish
this?
Compile-time evaluation is a red herring.

See it this way: Macros are a way to create blocks of code. HOFs that
return functions do the same: they take a few functions (and possibly
some value arguments), stick them together, and return the result. If
the HOF is evaluated at compile time (something that I'd expect if both
functions and values submitted to the HOF are constant), then you too
have a mechanism that creates a block of code.
The working point is slightly farther down the pipeline: not at the
abstract syntax level but at the semantics level (in practice, this
would be somewhere around "decorated abstract syntax", SSA
representation, basic blocks, or so).
> Macros do their job by
rewriting abstract syntax trees. (Lisp and macros go very well together
because in Lisp, you essentially program using a notation that maps
directly to an internal syntax tree, nearly without any parsing overhead.)

I agree that macros should work on the abstract syntax tree, not at the
lexical level like the C/C++ preprocessor.
Since the syntax tree is usually available at compile time, that's the
natural time to let macros do their job. However, in theory it wouldn't
be a problem to use macro expansion at runtime.

Hmm... it would be highly unpracticable, I'd think.
Do you have a keyword-style list of useful applications of functions?

I think you forgot a smiley - at least, that question is entirely silly.
If you have a real point to make, please make it explicit; I have too
little time to devote to decoding your intents. (And if you don't want
to spend time on trivialities, then please understand that I don't, too.)

Regards,
Jo
 
P

Peter Seibel

Joachim Durchholz said:
You're right, and made me rethink what's actually disturbing me about
macros.

Perhaps it's that I have to adapt to dual-mode (two-tier?) thinking:
I have to reason about both what the macros are doing and what the
software is doing. Alternatively, I could consider the macros as
"part of the language" and not reason about the macro code but about
their effects - in which case I have effectively augmented the
language by all macros that are in use.

I think you're right that you have to adopt a dual-mode of thinking.
When you're writing macros you're essentially extending the
compiler/language to recognize constructs that would otherwise be
meaningless.

Then, having written them, you use them as if they were in the
language all along. At one level this is no different from extending a
language by writing a function. That is, if you're working in a
language (like Common Lisp, Scheme, C, or--I imagine--any FPL) where
much of the "language" itself is implemented in terms of built-in
functions, if you write a new function you're extending the language
and after you've written it you can forget about the details of how it
works and just use it. The only difference between macros and
functions is that macros operate by generating code which then
performs actions as opposed to *being* code that performs actions. But
that level of indirection makes it easy to express things that would
otherwise be difficult (in my experience.)
Personally, I'd still prefer a compiler that's evaluating constant
expression.

Hmmm. If it will make you feel any better, macros are just fuctions
whose domain and range happens to be Lisp expressions. That happen to
be run by the compiler. So eventually the compiler is evaluating
constant expressions, just some of them were automatically derived
from the written source.
Is there anything that a macro does that can't be done by
preevaluating data structures that contain functions (or closures)?
At first glance, I'd say no, but then I don't know what macros are
used for in practice.

Well it depends whether you consider syntax to be "anything". I think
it was you who objected to one of my examples by saying, "that's just
syntactic sugar". Macros can (and many do) do large amount of
under-the-covers bookkeeping. For instance here are a few rules from a
grammar for a lexer for Java source code:

(defprod line-terminator () (/ #\newline (#\return (? #\newline))))

(defprod white-space () (/ #\space #\tab #\page line-terminator))

(defprod input () ((* input-element) (? #\Sub)))

(defprod input-element () (/ white-space comment token))

(defprod token () (/ identifier java-keyword literal separator operator))

DEFPROD is a macro that squirrels away the stuff on the right which is
an s-expy form of BNF. The rest of the grammar is more of the same. At
the bottom of the grammar file where the productions are diffined I
have this form:

(deflexer java-lexer (input)
(:)tokens identifier java-keyword literal separator operator)))

That DEFLEXER call (another macro) expands into a single parsing
function built out of all the productions created by DEFPROD calls,
appropriately wired together and embedded into code that takes care of
the stepping through the input and gather up values, etc. And that
function is compiled into extremely efficient code because all the
intercommunication between productions goes through lexical variables.
And the file containing these calls to DEFPROD and DEFLEXER is legal
Lisp source which I can feed to the compiler and get native machine
code back.

So I don't know if that is "anything" or not. I don't know how I would
write such a thing in Haskell, et al. but I know this is a *lot*
cleaner than what *I'd* be able to do in Java, Perl, Python, or C.
Um, well, yes, there is one thing that macros can do: extending
syntax in ways that aren't part of the original language syntax.
E.g. replacing all those parentheses by indentation, or something
similar un-Lispish. (Extending syntax in such ways is a mistake
IMHO, but YMMV. Anyway, I'm more interested in the question if
there's any /semantics/ that can be done via macros but not via
compile-time evaluation.)

Actually, changing the syntax is--if one thinks one must--is really
done by read-macros which are quite different. But most Lispers agree
with you--there's just not enough benefit to changing the syntax to be
worth it. Except for occasionally making a new syntax for expressing
certain frequently created literal objects that otherwise would
require a much more verbose creation form. (Someone gave a great
example the other day in another thread of an airline reservation
system (Orbitz I think) that has a special kind of object used to
represent the three-letter airport codes. Since they wanted to always
have the same object representing a given airport they needed to
intern the objets with the TLA as the key. But rather than writing
(intern-airport-code "BOS") everywhere, they wrote a reader macro that
let them write: #!BOS. Since this was an incredibly common operation
in their system, it was worth a tiny bit of new syntax. But note,
again, that's not *changing* the syntax so much as extending it.)
I believe it's not DEFMACRO that's complicating things, it's the
macros that it allows (see above).

Fair enough. But do you object to the ability to write new functions
on the grounds that that just means you have a lot of new functions to
learn and that complicates things needlessly? That's obviously a
rhetorical question but I am actually curious why you find them
different, if you do.
Agreed on all accounts (except that I don't know how "multilingual"
Lispers really are *g*).

Well, there is the problem that once folks find Lisp they tend to stop
looking for better things because what could be better than Lisp. ;-)
But most Lispers take a fairly circuitous path to Lisp and hit a bunch
of other languages before they find it.
Does anybody have a keyword-style list of useful applications of the
macro facilities?


"99% of all cases" is a pretty good argument actually :)
It's just that Pascal doesn't (want to) believe that it's enough for
type checking. His problem, not mine...


Agreed. I'm getting more and more convinced that it's not language
size or KISS issues that's setting me off, it's that "two-tier
thinking" that I (perhaps mistakenly?) associate with macros.

The funny thing is to me, when you say "two-tier thinking" that
perfectly describes how I think about the process of making
abstractions. Regardless of the *kind* of abstraction one is creating,
one has to be facile at switching mental gears between *building* the
abstraction and *using* it. You are probably so used to doing this
when writing functions that you don't even notice the switch. But
because macros are a bit strange you *notice* the switching and it
annoys you. I suspect that anyone who's capable of building functional
abstractions would--if they actually used macros--quickly learn to
switch gears equally smoothly when writing and using macros.
I wouldn't want HM typing if it were just beautiful theory.
HM typing happens to be a beautiful theory. Things are getting less
beautiful once you interact with the Real World (TM), which is
stateful - OTOH, Real World is a mess, so don't expect computing to be
beautiful anymore when there is interaction with it *g*. What
surprised me is how much of a computation can be separated from such
interaction. With the proper framework, one can even describe
interaction patterns (which are themselves stateless), feed these
patterns to the framework, and watch in amazement how the execution
engine follows these patterns. It's the kind of abstractive facility
I've been yearning for decades...
Lisp could do this just as well. It's just not done because taking the
shortcut and doing stateful computations directly is so much easier.
(And I don't pretend that functional languages are doing this kind of
thing perfectly right now. I think the potential in these ideas is
just beginning to be exploited - and what's available is already quite
impressive.)


Actually I'm trying to understand macros and macro usage right now,
without having to learn all the details of CL (which would be a bit of
overkill - I know it might not be enough, but then my time is limited
so I'm doing my best within the available budget).

Sure. Cheers.

-Peter
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top