Recreational Common Lisp :)

19 views
Skip to first unread message

Mark Conrad

unread,
May 6, 2003, 9:20:40 AM5/6/03
to
After many years of absence, I am rediscovering CL. When I did play
with Lisp back in the early 90's, it was strictly as a newbie.

I have no interest in becoming productive, just wanna have fun.

Among other shiny ornaments on the Common-Lisp tree, there are
"continuations", thanks to Paul Graham and his older book. (the entire
book is available free, online, name is "On Lisp")

THE FOLLOWING CODE WON'T WORK UNLESS PAUL GRAHAM'S MACROS ARE LOADED
FIRST - - -

Anyone interested in playing with this, let me know and I will post the
macros and a bit of other code along with them.

Anyhow -
Assume we have a simple 'progn' form:

(progn
(print 'first)
(print 'second)
(print 'third)
(print 'fourth)
(print 'fifth)
nil)

...and we want to create a continuation in it.

(progn
(print 'first)
(print 'second)
<== create a contin' here
(print 'third)
(print 'fourth)
(print 'fifth)
nil)


Now once our continuation is wedged in there, we are empowered to jump
out of our 'progn' form any time we want to.

If we want to come back to the progn form later and finish up what it
does, fine and dandy.

If we don't want to ever come back, that is also fine and dandy.

Okay, let's jam our continuation in:

(progn
(print 'first)
(print 'second)

(=bind () (=values)
(setq k #'(lambda ()

(print 'third)
(print 'fourth)
(print 'fifth)
nil) )))


Now when we run our simple progn form, it displays:
FIRST
SECOND
#<Anonymous Function #x1EC0ACBE>


Okay, the jump-out part works, now let's *use* the continuation we
created to "continue" the interupted progn-form.

(progn
(print 'first)
(print 'second)

(=bind () (=values)
(setq k #'(lambda ()

(print 'third)
(print 'fourth)
(print 'fifth)
nil) ))

(funcall k) )


Running the above progn form displays:

FIRST
SECOND
THIRD
FOURTH
FIFTH
NIL


Okay, we have our simple progn form 'spiked' with a continuation, so
now we can jump in and out of the progn form at will, anytime we want
to do so.

Here we do just that. Randomly, according to the "if" section of code,
we *might* jump out of the progn form after it prints FIRST, SECOND
and go to a function named "elsewhere". It takes 'elsewhere' about two
seconds to finish running, and elsewhere's last act is to use our
continuation to kick control back to our humble 'progn' form whereupon
the 'progn' form "continues" from where it was interupted, printing
THIRD, FOURTH, FIFTH.

(progn
(print 'first)
(print 'second)

(=bind () (=values)
(setq k #'(lambda ()

(print 'third)
(print 'fourth)
(print 'fifth)
nil) ))

(if (= (random 2) 0)
(elsewhere)
(funcall k) ))


Mark-

_ XL1201 _ Sebek _ Budo _ Kafka @hotmail.com Franz Kafka

unread,
May 6, 2003, 10:07:27 AM5/6/03
to

I was intrested in learning about A.I.
I learned about Lisp because most A.I. programs were
written in Lisp. I than came to love Lisp as a language
coming from Basic I picked it up rather quick.

When I stated learning C at my Community College I realized how
lucky I was for choosing Lisp.

I could do a lot in Lisp that I couldn't even approch in C--when I
tried to rewrite some applications I've written in Lisp into C to
learn that language I realized that one line of Lisp code usually
required several lines of C code--then I realized why the people who
do A.I. choose Lisp--it's easier to use for the harder problems. And, it's
easier to extend.


Mark Conrad

unread,
May 6, 2003, 4:06:11 PM5/6/03
to
In article <060520030623188998%nos...@iam.invalid>, Mark Conrad
<nos...@iam.invalid> wrote:

> Anyone interested in playing with this, let me know and I will post the
> macros and a bit of other code along with them.

Here are Paul Graham's six macros from his "On Lisp" book.

Copy and paste *everything* from between the asterisk lines to your
own file. This code is necessary to be loaded into Lisp _before_
the examples in this thread will run.


;****************************************

(defun group (source n)
(if (endp source)
nil
(let ((rest (nthcdr n source)))
(cons (if (consp rest)
(subseq source 0 n) source)
(group rest n)) )))

(defmacro abbrev (short long)
`(defmacro ,short (&rest args)
`(,',long ,@args)))


(defmacro abbrevs (&rest names)
`(progn
,@(mapcar #'(lambda (pair)
`(abbrev ,@pair))
(group names 2) )))

(abbrevs
=setq
define-symbol-macro)


;; Below are Paul Graham's six macros. About the only changes
;; that I made were to change his "*cont*" to "%cont%", in order
;; to emphasize that %cont% is not a dynamically-scoped
;; variable.
;;
;; Another change I made was to use "=setq" to ensure that %cont%
;; does not act like a dynamically-scoped variable.
;;
;; =setq is just a convenient shorter abbreviation for CL's built-in
;; macro named "define-symbol-macro"


(=setq
%cont%
#'(lambda (&rest args)
(if (cdr args)
args
(car args) )))

(defmacro =lambda (parms &body body)
`#'(lambda (%cont% ,@parms) ,@body))

(defmacro =defun (name parms &body body)
(let ((f (gensym)))
`(progn
(defmacro ,name ,parms
`(,',f %cont% ,,@parms))
(defun ,f (%cont% ,@parms) ,@body) )))

(defmacro =bind (parms expr &body body)
`(let ((%cont% #'(lambda ,parms ,@body))) ,expr))

(defmacro =values (&rest retvals)
`(funcall %cont% ,@retvals))

(defmacro =funcall (fn &rest args)
`(funcall ,fn %cont% ,@args))

(defmacro =apply (fn &rest args)
`(apply ,fn %cont% ,@args))

;*******************************************
;; End of Paul Graham's six macros from his "On Lisp" book.


Mark-

Mark Conrad

unread,
May 6, 2003, 4:06:21 PM5/6/03
to
In article <zkPta.4644$kF3....@news02.roc.ny.frontiernet.net>, Franz
Kafka < @> wrote:

> When I stated learning C at my Community College I realized how
> lucky I was for choosing Lisp.
>
> I could do a lot in Lisp that I couldn't even approch in C--when I
> tried to rewrite some applications I've written in Lisp into C to
> learn that language I realized that one line of Lisp code usually
> required several lines of C code--then I realized why the people who
> do A.I. choose Lisp--it's easier to use for the harder problems. And, it's
> easier to extend.

Yes, I agree.

A lot of AI problems are very complex in nature.

With Lisp, a person has the freedom to to make a program in "layers".

The top-layer of a complex Lisp program can look almost trivial in
nature, making it very easy to "follow-the-flow" of logic in one's own
program.

One can't appreciate how important this is, until one has gotten "lost"
in one's own program code, as the complexity of the program builds up
and overwhelms the programmer.

That is one reason why tools like "continuations" have to be used with
extreme care, because they aggravate the perceived-complexity of Lisp
code, making it hard to follow-the-flow of cracking a problem.

Mark-

Mark Conrad

unread,
May 6, 2003, 4:26:06 PM5/6/03
to
In article <060520030623188998%nos...@iam.invalid>, Mark Conrad
<nos...@iam.invalid> wrote:

> ...lotsa strange stuff...<g>

Notice that we have succeeded in demonstrating continuations in CL by
using only two of Paul Graham's six macros. ( "=bind" and "=values")

It is inconvenient to have to run the progn form just to demonstrate
continuations. It would be nice if we could put the progn form into a
function named "demo".

Unfortunately, when we are dealing with macros as we are doing now,
subtle 'bugs' can occur due tothe way that CL handles macros.

I tried throwing our simpleprogn-form into a regular function named
"demo", but the progn form 'broke' and ceased to produce random output
displays, as it was designed to do.

Below is the only way I know of (presently) to preserve correct way
that our progn form runs.

(defvar demo)

(setq demo
(quote (progn
(print 'first)
(print 'second)

(=bind () (=values)
(setq k #'(lambda ()

(print 'third)
(print 'fourth)
(print 'fifth)
nil) ))

(if (= (random 2) 0)
(elsewhere)

(funcall k) ))) )


Now we can run demo, and it will flip between the two types of output
displays in a random manner, as it should.

Typical runs of (eval demo) below -

Whenever it prints the line WENT-ELSEWHERE-FOR-AWHILE
...a little two-second delay occurs to simulate the time spent
executing the function "elsewhere"


(eval demo)
FIRST
SECOND
WENT-ELSEWHERE-FOR-AWHILE
THIRD
FOURTH
FIFTH
NIL


(eval demo)


FIRST
SECOND
THIRD
FOURTH
FIFTH
NIL


(eval demo)
FIRST
SECOND
WENT-ELSEWHERE-FOR-AWHILE
THIRD
FOURTH
FIFTH
NIL


(eval demo)
FIRST
SECOND
WENT-ELSEWHERE-FOR-AWHILE
THIRD
FOURTH
FIFTH
NIL


We have not done anything really interesting with continuations yet,
but what-the-heck, we are just starting to learn this stuff.

Mark-

Joe Marshall

unread,
May 6, 2003, 4:29:06 PM5/6/03
to
Mark Conrad <nos...@iam.invalid> writes:

> ;; Below are Paul Graham's six macros. About the only changes
> ;; that I made were to change his "*cont*" to "%cont%", in order
> ;; to emphasize that %cont% is not a dynamically-scoped
> ;; variable.
> ;;
> ;; Another change I made was to use "=setq" to ensure that %cont%
> ;; does not act like a dynamically-scoped variable.

Well.... it definitely won't behave like a dynamically scoped
variable, but it won't behave quite like a lexically scoped one,
either. You will have some strange behavior in the edge cases.

Since what you want is a `top-level' value for %cont% in those cases
where it is not lexically bound, your best bet is to set the
symbol-value.

(eval-when (:load-toplevel :execute)
(setf (symbol-value '%cont%)


(lambda (&rest args)
(if (cdr args)
args

(car args)))))

Mark Conrad

unread,
May 7, 2003, 8:25:05 AM5/7/03
to
In article <8ytjdd...@ccs.neu.edu>, Joe Marshall <j...@ccs.neu.edu>
wrote:

> > ;; Another change I made was to use "=setq" to ensure that %cont%
> > ;; does not act like a dynamically-scoped variable.
>
> Well.... it definitely won't behave like a dynamically scoped
> variable, but it won't behave quite like a lexically scoped one,
> either. You will have some strange behavior in the edge cases.
>
> Since what you want is a `top-level' value for %cont% in those cases
> where it is not lexically bound, your best bet is to set the
> symbol-value.
>
> (eval-when (:load-toplevel :execute)
> (setf (symbol-value '%cont%)
> (lambda (&rest args)
> (if (cdr args)
> args
> (car args)))))

Thanks, I wish I knew what I am doing with this stuff, instead of
groping around in the dark.

What I am primarily worried about is the fact that the HyperSpec does
not spell out how to handle top level variable-binding.
(am I correct in this assumption?)

If a CL implementor decides to make all his top level variables have
dynamic scope, the HyperSpec might not stop him. That would "break"


Paul Graham's six macros.


Wow! - I just skim-read the definition of eval-when in CLtL2.

They were not kidding about "Its uses are relatively esoteric".

I will have to re-read that definition at least ten times before it
even begins to make sense to me!

I think the best way I can appreciate what eval-when does is to create
a program where a continuation "relies" on the value of %cont% as being
the initial defined value of %cont%.

I assume my present initial-defined-value of %cont% might "break" in
such cases, whereas the eval-when version would be less likely to
break.

Mark-

Mark Conrad

unread,
May 7, 2003, 6:31:45 PM5/7/03
to
In article <8ytjdd...@ccs.neu.edu>, Joe Marshall <j...@ccs.neu.edu>
wrote:

> You will have some strange behavior in the edge cases.

AAARG !!! - I already ran into a lot of those "edge cases" :-(

Your "eval-when" suggestion really came to my rescue.

Now code works as I want it to work, with eval-when in the act.

Here is the transcript as to how things stand now.

Welcome to the demo version of Macintosh Common Lisp Version 4.3!

? (define-symbol-macro %cont% 'foo)
%CONT%


? %cont%
FOO


? (eval-when (:load-toplevel :execute)


(setf (symbol-value '%cont%)
(lambda (&rest args)
(if (cdr args)
args
(car args)) )))

#<Anonymous Function #x1EFB8686>


? (let () (defun test () (print %cont%)))
TEST


? (test)
FOO
FOO


? %cont%
FOO


? (unintern '%cont%)
T


? (test)
FOO
FOO
?


? %cont%
> Error: Unbound variable: %CONT%
> While executing: "Unknown"
> Type Command-/ to continue, Command-. to abort.
> If continued: Retry getting the value of %CONT%.

That error message is as it should be, after the unintern.


Thanks again for the eval-when suggestion.

Mark-

Nils Goesche

unread,
May 7, 2003, 7:09:13 PM5/7/03
to
Mark Conrad <nos...@iam.invalid> writes:

> ? (eval-when (:load-toplevel :execute)
> (setf (symbol-value '%cont%)
> (lambda (&rest args)
> (if (cdr args)
> args
> (car args)) )))

I do not have the slightest idea what you are trying to do here,
but I seem to remember that I told you quite a while ago that if
you simply do

(define-symbol-macro *cont* #'identity)

instead of the global setq, Graham's continuation macros will
work just fine.

Regards,
--
Nils Gösche
Ask not for whom the <CONTROL-G> tolls.

PGP key ID #xD26EF2A0

Mark Conrad

unread,
May 7, 2003, 7:10:16 PM5/7/03
to
In article <060520031307021934%nos...@iam.invalid>, Mark Conrad
<nos...@iam.invalid> wrote:

> ...some erroneous stuff...

Here is the *CORRECTED* version of Paul Graham's "six macros" code
from his 1994 "On Lisp" book

Joe Marshall kindly pointed out that some of my added code would break
Paul's macros, and suggested that I use the CL "eval-when" here.

After some brief tests, the addition of eval-when does indeed appear to
eliminate difficulties experienced by me when a continuation tries to
go to toplevel

Copy and paste *everything* from between the asterisk lines to your
own file. This code is necessary to be loaded into Lisp _before_
the examples in this thread will run.

;; CORRECTED VERSION - REPLACE YOUR OLDER VERSION
;****************************************

(abbrevs
=setq
define-symbol-macro)

;;
;; Regarding the "=setq" form immediately below, it might not be
;; necessary however I think it should be left in because a few CL
;; implementors might try to turn toplevel variables like %cont% into
;; special variables, which would break Paul Graham's six macros.

(=setq
%cont%
#'(lambda (&rest args)
(if (cdr args)
args
(car args) )))

(eval-when (:load-toplevel :execute)
(setf (symbol-value '%cont%)


(lambda (&rest args)
(if (cdr args)
args

(car args)) )))

Mark Conrad

unread,
May 7, 2003, 7:43:21 PM5/7/03
to
In article <87el3ap...@darkstar.cartan>, Nils Goesche
<n...@cartan.de> wrote:

> > ? (eval-when (:load-toplevel :execute)
> > (setf (symbol-value '%cont%)
> > (lambda (&rest args)
> > (if (cdr args)
> > args
> > (car args)) )))
>
> I do not have the slightest idea what you are trying to do here,
> but I seem to remember that I told you quite a while ago that if
> you simply do
>
> (define-symbol-macro *cont* #'identity)
>
> instead of the global setq, Graham's continuation macros will
> work just fine.

Hi Nils, thanks for the post, I can use all the help I can get :)

Joe Marshall and myself were thrashing out a situation that occurs when
a continuation tries to go all the way to toplevel and terminate the
entire program.

As you know, seldom are continuations used in that fashion, usually
they just hop around inside the program.

For that matter, a standard "throw" would get us to toplevel and
program-termination if that was really what we wanted to do.

Also, if I wanted to, I could setq the initial global value of
"*cont*" (or %cont% ) to 'foo instead of "#'identity" and Paul's
macros would still work as advertised, except in the case that I
refered to above. (a very unlikely special case)

There is also a nasty side issue here. The HyperSpec does not "forbid"
a CL implementor from causing all his toplevel variables to be special
variables, which would definately break Paul's macros.

So far, no CL implementations do that nasty trick, but what is to stop
them - nothing in the HyperSpec that I am aware of would stop them.

BTW, the business of departing from #'identity is Paul's code at the
bottom of page 395 of his "On Lisp" book, very handy whenever one wants
to return multiple values to toplevel when terminating the program.

Hope this explains what is going on -

Mark-

Mark Conrad

unread,
May 7, 2003, 7:49:39 PM5/7/03
to
In article <87el3ap...@darkstar.cartan>, Nils Goesche
<n...@cartan.de> wrote:

> (define-symbol-macro *cont* #'identity)

Nils, that by itself, without the help of "eval-when", broke on me.

Give me a little time and I will find my notes about the specific
situation where it broke, and I will get back to you.

Mark-

Thomas F. Burdick

unread,
May 7, 2003, 9:43:32 PM5/7/03
to nobody
Mark Conrad <nos...@iam.invalid> writes:

> In article <87el3ap...@darkstar.cartan>, Nils Goesche
> <n...@cartan.de> wrote:
>
> > > ? (eval-when (:load-toplevel :execute)
> > > (setf (symbol-value '%cont%)
> > > (lambda (&rest args)
> > > (if (cdr args)
> > > args
> > > (car args)) )))
> >
> > I do not have the slightest idea what you are trying to do here,
> > but I seem to remember that I told you quite a while ago that if
> > you simply do
> >
> > (define-symbol-macro *cont* #'identity)
> >
> > instead of the global setq, Graham's continuation macros will
> > work just fine.
>
> Hi Nils, thanks for the post, I can use all the help I can get :)

Not that you listen.

> Also, if I wanted to, I could setq the initial global value of
> "*cont*" (or %cont% ) to 'foo instead of "#'identity" and Paul's
> macros would still work as advertised, except in the case that I
> refered to above. (a very unlikely special case)

Except that you'd be invoking undefined behavior. There is no concept
of global lexicals in CL.

> There is also a nasty side issue here. The HyperSpec does not "forbid"
> a CL implementor from causing all his toplevel variables to be special
> variables, which would definately break Paul's macros.

This is not a side issue, this is at the heart of the matter.

> So far, no CL implementations do that nasty trick, but what is to stop
> them - nothing in the HyperSpec that I am aware of would stop them.

Yes, a major CL implementation (CMUCL) does just this, although it's
*not* a nasty trick. A toplevel SETQ on a symbol that has not been
DEFVARed has no defined meaning. DEFINE-SYMBOL-MACRO was added to the
language to address *exactly* the use that Graham made of a toplevel
SETQ here.

> BTW, the business of departing from #'identity is Paul's code at the
> bottom of page 395 of his "On Lisp" book, very handy whenever one wants
> to return multiple values to toplevel when terminating the program.
>
> Hope this explains what is going on -

It sure explains that you don't pay attention to anything you don't
want to hear.

--
/|_ .-----------------------.
,' .\ / | No to Imperialist war |
,--' _,' | Wage class war! |
/ / `-----------------------'
( -. |
| ) |
(`-. '--.)
`. )----'

Mark Conrad

unread,
May 7, 2003, 11:17:08 PM5/7/03
to
In article <87el3ap...@darkstar.cartan>, Nils Goesche
<n...@cartan.de> wrote:

> ...lotsa interesting stuff...

I could not locate the example I was looking for about
define-symbol-macro breaking, so I whiped up another example quickly.
It is not as good an example because I get a compiler 'warning' in this
case, but it will get across the idea.

Example #1 with eval-when
*********************************************


Welcome to the demo version of Macintosh Common Lisp Version 4.3!

? (define-symbol-macro %cont% #'identity)
%CONT%


? (eval-when (:load-toplevel :execute)
(setf (symbol-value '%cont%)
(lambda (&rest args)
(if (cdr args)
args
(car args)))))

#<Anonymous Function #x1EFB84DE>


? (define-symbol-macro k 'meow)
K


? (let ((r %cont%))
(defun test () (print(funcall %cont% 'woof)) (setq r 'bow-wow) r
) )
;Compiler warnings :
; Undeclared free variable %CONT%, in an anonymous lambda form.
TEST

? (test)
WOOF
BOW-WOW


? (funcall %cont% k)
MEOW
?
*******************************************


Example #2 without eval-when
#################################


Welcome to the demo version of Macintosh Common Lisp Version 4.3!

? (define-symbol-macro %cont% #'identity)
%CONT%


? (define-symbol-macro k 'meow)
K


? (let ((r %cont%))
(defun test () (print(funcall %cont% 'woof)) (setq r 'bow-wow) r
) )

;Compiler warnings :
; Undeclared free variable %CONT%, in an anonymous lambda form.
> Error: Unbound variable: %CONT%
> While executing: #<Anonymous Function #x1EF2B69E>


> Type Command-/ to continue, Command-. to abort.
> If continued: Retry getting the value of %CONT%.

See the RestartsŠ menu item for further choices.
1 >
#################################

Mark-

Mark Conrad

unread,
May 8, 2003, 6:00:03 AM5/8/03
to
In article <xcv8yti...@conquest.OCF.Berkeley.EDU>, Thomas F.
Burdick <t...@conquest.OCF.Berkeley.EDU> wrote:

> > Hi Nils, thanks for the post, I can use all the help I can get :)
>
> Not that you listen.

Oh I listen. If what you write has merit, I listen very closely.

If what you write has no merit (IMO of course), I ignore it.


> > Also, if I wanted to, I could setq the initial global value of
> > "*cont*" (or %cont% ) to 'foo instead of "#'identity" and Paul's
> > macros would still work as advertised, except in the case that I
> > refered to above. (a very unlikely special case)
>
> Except that you'd be invoking undefined behavior.

So what? If it is good enough for a CL guru like Paul Graham to use
"undefined-behavior", it is also good enough for me to do the same
thing. The only thing that concerns me whenever I use
"undefined-behavior" is the issue of whether my code will run on all
HyperSpec-compliant CL implementations.

It appears that the combination of "define-symbol-macro" and
"eval-when" will allow my continuation code to run on all compliant
implementations of CL, so what is the big deal?


> > There is also a nasty side issue here. The HyperSpec does not "forbid"
> > a CL implementor from causing all his toplevel variables to be special
> > variables, which would definately break Paul's macros.
>
> This is not a side issue, this is at the heart of the matter.

I disagree. To me, CL is a tool. As such, I use it to accomplish
results. I care less about whether the tool I am using has the
blessing of the HyperSpec, as long as that tool works with all
HyperSpec compliant CL implementations.


> There is no concept of global lexicals in CL.

That may be correct, depending on your interpretation of various
passages in the HyperSpec. If you are thinking of:

'lexical scope of a toplevel variable in the toplevel environment'

...then things start getting a little hazy.

One interpretation could be that the variable in question in the
toplevel environment is "visible" to every part of your program, except
when shadowed by a variable with the same name. If the variable in
question is not declared to have dynamic scope, then you have only one
other type of scope that the variable can have, namely lexical scope.

There are only two types of scope when writing about the "scope" of a
variable, dynamic scope or lexical scope.

Now whether the variable scope is "blessed" by the HyperSpec or whether
the scope of the variable is "undefined" is beside the point, because
the scope of a variable *still* has to be one or the other,
dynamically-scoped or lexically-scoped in so far as how it acts in your
program.

For example, in my MCL ver 4.3 all toplevel variables created by setq
act as if they are lexically-scoped throughout the program.

You say that CMUCL toplevel variables are different. That means to me
that toplevel variables in CMUCL act as if they were
dynamically-scoped.


> A toplevel SETQ on a symbol that has not been
> DEFVARed has no defined meaning.

It still has to act in the program in only one of two ways, either as
if it is dynamically-scoped or lexically-scoped.

For example, a toplevel SETQed variable in my MCL acts like it is
lexically-scoped throughout my program.

The only reason I am using "define-symbol-macro" and "eval-when" is to
ensure that my code will run properly on other CL implementations like
CMUCL for example.


> > Hope this explains what is going on -
>
> It sure explains that you don't pay attention to anything you don't
> want to hear.

Of course not, neither do you.

Mark-

Matthew Danish

unread,
May 8, 2003, 6:35:23 AM5/8/03
to
On Thu, May 08, 2003 at 10:00:03AM +0000, Mark Conrad wrote:
> In article <xcv8yti...@conquest.OCF.Berkeley.EDU>, Thomas F.
> Burdick <t...@conquest.OCF.Berkeley.EDU> wrote:
>
> > > Hi Nils, thanks for the post, I can use all the help I can get :)
> >
> > Not that you listen.
>
> Oh I listen. If what you write has merit, I listen very closely.
>
> If what you write has no merit (IMO of course), I ignore it.

The problem is that you haven't the knowledge to judge merit yet. You have
demonstrated time and time again that you discard informative material.

> > > Also, if I wanted to, I could setq the initial global value of
> > > "*cont*" (or %cont% ) to 'foo instead of "#'identity" and Paul's
> > > macros would still work as advertised, except in the case that I
> > > refered to above. (a very unlikely special case)
> >
> > Except that you'd be invoking undefined behavior.
>
> So what? If it is good enough for a CL guru like Paul Graham to use
> "undefined-behavior", it is also good enough for me to do the same
> thing.

So if Paul Graham jumped off the Brooklyn Bridge, you would do so too?

We have already told you several times, but you never listen: Paul Graham wrote
his book just before the ANSI standard was finalized. His code therefore
reflects a slightly older style which IS NO LONGER COMPLETELY CORRECT. The
book is correct enough to be useful. But it is not the epitome of perfection.

> The only thing that concerns me whenever I use "undefined-behavior" is the
> issue of whether my code will run on all HyperSpec-compliant CL
> implementations.

If behavior is "undefined" YOU CANNOT USE IT AND GUARENTEE SIMILAR BEHAVIOR ON
ALL CONFORMING IMPLEMENTATIONS.

What you are trying to do is very similar to trying to work with the result of
dividing 1 by 0. Since you have demonstrated much ignorance, I will inform you
that the result of 1/0 is UNDEFINED.

> It appears that the combination of "define-symbol-macro" and
> "eval-when" will allow my continuation code to run on all compliant
> implementations of CL, so what is the big deal?
>
> > > There is also a nasty side issue here. The HyperSpec does not "forbid"
> > > a CL implementor from causing all his toplevel variables to be special
> > > variables, which would definately break Paul's macros.
> >
> > This is not a side issue, this is at the heart of the matter.
>
> I disagree. To me, CL is a tool. As such, I use it to accomplish
> results. I care less about whether the tool I am using has the
> blessing of the HyperSpec, as long as that tool works with all
> HyperSpec compliant CL implementations.

Are you mad? You don't care that X is false, so long as X is true. At least I
understand your world now; when you have a contradiction, you can prove
anything! Not to mention invoking religion. No wonder.

> > There is no concept of global lexicals in CL.
>
> That may be correct, depending on your interpretation of various
> passages in the HyperSpec. If you are thinking of:
>
> 'lexical scope of a toplevel variable in the toplevel environment'
>
> ...then things start getting a little hazy.
>
> One interpretation could be that the variable in question in the
> toplevel environment is "visible" to every part of your program, except
> when shadowed by a variable with the same name. If the variable in
> question is not declared to have dynamic scope, then you have only one
> other type of scope that the variable can have, namely lexical scope.
>
> There are only two types of scope when writing about the "scope" of a
> variable, dynamic scope or lexical scope.
>
> Now whether the variable scope is "blessed" by the HyperSpec or whether
> the scope of the variable is "undefined" is beside the point, because
> the scope of a variable *still* has to be one or the other,
> dynamically-scoped or lexically-scoped in so far as how it acts in your
> program.
>
> For example, in my MCL ver 4.3 all toplevel variables created by setq
> act as if they are lexically-scoped throughout the program.
>
> You say that CMUCL toplevel variables are different. That means to me
> that toplevel variables in CMUCL act as if they were
> dynamically-scoped.

The key point is not that they are some kind of "Weird scope" but that you
cannot know which kind they will be. You are also making a false assumption:
that some variable would be created at all! Who said that "undefined" means
"create a variable of arbitrary scope"?

For all you know, typing "(setq a 1)" into a freshly loaded Lisp could cause
demons to fly out of your nose!

Would you bet your life that any arbitrarily chosen CL-conforming
implementation chooses to scope said variables in a particular way, if at all?

> > > Hope this explains what is going on -
> >
> > It sure explains that you don't pay attention to anything you don't
> > want to hear.
>
> Of course not, neither do you.

What are you, some kind of paranoid lunatic? You are making a good case for
corporal punishment in schools (particularly the grade where they teach you how
to read).

Prove me wrong. Or stop making broad statements about an issue which you are
clueless about, at least in a forum that better-informed people are reading.

--
; Matthew Danish <mda...@andrew.cmu.edu>
; OpenPGP public key: C24B6010 on keyring.debian.org
; Signed or encrypted mail welcome.
; "There is no dark side of the moon really; matter of fact, it's all dark."

Pascal Costanza

unread,
May 8, 2003, 7:18:20 AM5/8/03
to
Mark Conrad wrote:

> So what? If it is good enough for a CL guru like Paul Graham to use
> "undefined-behavior", it is also good enough for me to do the same
> thing. The only thing that concerns me whenever I use
> "undefined-behavior" is the issue of whether my code will run on all
> HyperSpec-compliant CL implementations.

Section 1.5 of the HyperSpec tells you _exactly_ what you can and must
not assume with regard to portability of your programs across conforming
implementations. See
http://www.lispworks.com/reference/HyperSpec/Body/01_e.htm


Pascal

--
Pascal Costanza University of Bonn
mailto:cost...@web.de Institute of Computer Science III
http://www.pascalcostanza.de Römerstr. 164, D-53117 Bonn (Germany)

Nils Goesche

unread,
May 8, 2003, 8:16:41 AM5/8/03
to
Mark Conrad <nos...@iam.invalid> writes:

> Example #2 without eval-when
> #################################
> Welcome to the demo version of Macintosh Common Lisp Version 4.3!
>
> ? (define-symbol-macro %cont% #'identity)
> %CONT%
>
>
> ? (define-symbol-macro k 'meow)
> K
>
>
>
> ? (let ((r %cont%))
> (defun test () (print(funcall %cont% 'woof)) (setq r 'bow-wow) r
> ) )
>
> ;Compiler warnings :
> ; Undeclared free variable %CONT%, in an anonymous lambda form.
> > Error: Unbound variable: %CONT%
> > While executing: #<Anonymous Function #x1EF2B69E>
> > Type Command-/ to continue, Command-. to abort.
> > If continued: Retry getting the value of %CONT%.

> See the Restartsžª menu item for further choices.
> 1 >
> #################################

Heh. Looks like a bug to in MCL to me. Please learn to indent your
code correctly. The last form should look like

(let ((r %cont%))
(defun test ()

(print (funcall %cont% 'woof))
(setq r 'bow-wow)
r))

As a fix, you might try

(eval-when (:load-toplevel :compile-toplevel :execute)
(define-symbol-macro %cont% #'identity))

Does it work then?

Regards,
--
Nils Gösche
"Don't ask for whom the <CTRL-G> tolls."

PGP key ID 0x0655CFA0

Nikodemus Siivola

unread,
May 8, 2003, 9:30:24 AM5/8/03
to
Mark Conrad <nos...@iam.invalid> wrote:

What I personally find amazing is your ability to twist evidence into shape
that is pleasing to you, no matter what happens to the integrity of the
evidence.

>> Except that you'd be invoking undefined behavior.

> So what? If it is good enough for a CL guru like Paul Graham to use
> "undefined-behavior", it is also good enough for me to do the same
> thing. The only thing that concerns me whenever I use

How many times have people explained this to you? I've lost count. Grahams
book was published *before* there was an ANSI standard.

And re. undefined behaviour:

>> This is not a side issue, this is at the heart of the matter.

> I disagree. To me, CL is a tool. As such, I use it to accomplish
> results. I care less about whether the tool I am using has the

How many times have people examplained *this* to you? By invoking undefined
behaviour you have no guarantee that what you do will work tomorrow. Not
even on the same version of Lisp you have now.

> For example, in my MCL ver 4.3 all toplevel variables created by setq
> act as if they are lexically-scoped throughout the program.

How many times have *you* said: "Oh, now I see it. Now I understand why I
should not do this." ?

>> A toplevel SETQ on a symbol that has not been
>> DEFVARed has no defined meaning.

> It still has to act in the program in only one of two ways, either as
> if it is dynamically-scoped or lexically-scoped.

No, it can even signal en error. Or as someone so succintly put it: it can
fire missiles to France.

FWIW: I believe that the reason most implementations allow this is to let
you stuff things into toplevel variables during an interactive session
without first defining them.

Cheers,

-- Nikodemus

_ XL1201 _ Sebek _ Budo _ Kafka @hotmail.com Franz Kafka

unread,
May 8, 2003, 10:00:41 AM5/8/03
to

"Matthew Danish" <mda...@andrew.cmu.edu> wrote in message
news:2003050806...@mapcar.org...

>
> So if Paul Graham jumped off the Brooklyn Bridge, you would do so too?
>
> We have already told you several times, but you never listen: Paul Graham
wrote
> his book just before the ANSI standard was finalized. His code therefore
> reflects a slightly older style which IS NO LONGER COMPLETELY CORRECT.
The
> book is correct enough to be useful. But it is not the epitome of
perfection.
>

If you are writing code that is CLtL1, or CLtL2 compliant you should
advertise it as such rather than trying to do cheap hacks to make it ANSI
compliant--if you know what the code is doing and are not just blindly
following Garham you might even rewrite it to work under ANSI.

If you really feel the need you could use the #+ #- macro's to
make sure it works under most implementations. Then you would have to tell
people what Lisp's it worked under ala Screamer.

You could also write Lisp code to add the features missing from ANSI but
even that might not be portable.

If you want it to run across all ANSL compliant Lisps it's going to take
some more work that copying code from "On Lisp." + If you want it to also
work with CLtL1 & CLtL2 Lisps it will take even more work.

Peter Novig's Paradigms book gives a few examples of how much work this
could take for a simple timer function. + He has a Scheme compiler that is
written in Lisp and has call/cc BTW, I don't know if it is ANSI compliant or
not. & you can only use his call/cc with the Scheme not the Lisp--he warns
that what you are trying to do is non-trivial & requires a Code-Walker. This
must be diff. to write--I've read a lot of Lisp books and only LiSP in Small
Pieces an advanced text talks about them, and no book I've found talks about
how to write one in Lisp.


David Steuber

unread,
May 8, 2003, 3:20:57 PM5/8/03
to
Matthew Danish <mda...@andrew.cmu.edu> writes:

> For all you know, typing "(setq a 1)" into a freshly loaded Lisp could cause
> demons to fly out of your nose!

That would indeed be a most unexpected behavior. I think something
like beer or coffee would have a higher probability of flying out of
the nose, with devestating effects to a computer keyboard.

Matthew Danish

unread,
May 8, 2003, 3:48:32 PM5/8/03
to

Hrm. Do you have any references for such a statement? Perhaps someone should
commission a study to determine for various objects the probability that they
will fly out of your nose when you invoke undefined behavior. That would
certainly clear this matter up. And on a per-implementation basis too; for
example: with CLISP, the probability of Richard Stallman emerging from your
olfactory organ is probably a great deal higher than with Allegro.

One possible drawback I could see is that there might be a call for an
extension to the CL standard for a `tissue system' by which these objects may
be caught and dealt with, and perhaps a way to resume from a sniffle.

P.S. I am sure that nasal demons, or even RMS, could cause quite a bit of
damage to your keyboard and more, depending on how they landed upon emerging
from your nose, and with how much energy they were ejected.

Mark Conrad

unread,
May 8, 2003, 4:22:16 PM5/8/03
to
In article <lyd6it6...@cartan.de>, Nils Goesche <car...@cartan.de>
wrote:

> Heh. Looks like a bug to in MCL to me.

Anything is possible in that piece of code. I will take the easy way
out and use eval-when, as long as it works:

**********************************************


Welcome to the demo version of Macintosh Common Lisp Version 4.3!

? (define-symbol-macro %cont% #'identity)
%CONT%

? (eval-when (:load-toplevel :execute)
(setf (symbol-value '%cont%)
(lambda (&rest args)
(if (cdr args)
args
(car args)))))
#<Anonymous Function #x1EFB84DE>

? (define-symbol-macro k 'meow)
K


? (let ((r %cont%))
(defun test ()

(print (funcall %cont% 'woof))
(setq r 'bow-wow) r ))

;Compiler warnings :
; Undeclared free variable %CONT%, in an anonymous lambda form.

TEST


? (test)
WOOF
BOW-WOW


? (funcall %cont% k)
MEOW
?

************************************************

Actually, eval-when frightens me. At the present time, I find it
extremely difficult to comprehend that built-in CL function.

None of my tutorials explain eval-when, so I am left with trying to
comprehend it by reading CLtL2.

Not an ideal way to learn.

Mark-

Mark Conrad

unread,
May 8, 2003, 4:22:25 PM5/8/03
to
In article <2003050806...@mapcar.org>, Matthew Danish
<mda...@andrew.cmu.edu> wrote:

> So if Paul Graham jumped off the Brooklyn Bridge, you would do so too?

Darn tootin', I would be right behind him. We would both gracefully
glide down to earth on our parafoils.

I have immense respect for whatever Paul Graham writes, with the
possible exception of some stray example code in his books.


> For all you know, typing "(setq a 1)" into a freshly loaded Lisp could
> cause demons to fly out of your nose!

That is why I always wear a nose-clip when typing "(setq a 1)".


> Prove me wrong.

Why should I bother. That is a bunch of work.


> Or stop making broad statements about an issue which you are
> clueless about, at least in a forum that better-informed people are
> reading.

I most certainly will not! Making those broad statements has a decided
benefit for me. If my statement is wrong, I get ample replies
informing me exactly how the cookie crumbles.

From those replies, I can ignore the hate mongers, and sift out
knowledge that is understandable to me.

Why should I abandon such a good learning tool.

Other Lisp newbies won't be influenced by my remarks, because I have
stated up front that I am a Lisp newbie also, many times.

My "clueless" broad remarks merely reflect the present stage of my
understanding, which is subject to daily change and improvement.

That is why I get a kick out of those guys who dig up old erroneous
remarks of mine, that I have long since rejected as wrong, in their
vain efforts to discredit me.

I just ignore them, they obviously have some sort of ego thing where
they feel the need to look clever-by-comparison to a newbie.

If you can't stand the heat in the "clueless" kitchen, stay out.

Mark-

Mark Conrad

unread,
May 8, 2003, 4:22:33 PM5/8/03
to
In article <b9deds$o5m$1...@f1node01.rhrz.uni-bonn.de>, Pascal Costanza
<cost...@web.de> wrote:

> Section 1.5 of the HyperSpec tells you _exactly_ what you can and must
> not assume with regard to portability of your programs across conforming
> implementations. See
> http://www.lispworks.com/reference/HyperSpec/Body/01_e.htm


Do you happen to know where I can buy a hardcopy of the HyperSpec.

Just curious if a hardcopy is available, and where.

My Mac, running OS 10.2.4 (so-called "OS X") - froze up when I was
using the downloadable version. That is the first time in six months
that OS X froze on anything.

I usually leave my Mac powered up all the time. I have plenty of RAM
in my "Pismo" powerbook, 1024 MBs, so that was probably not the cause
of the freeze.

Mark-

Mark Conrad

unread,
May 8, 2003, 4:22:41 PM5/8/03
to
In article <b9dm5g$59t09$1...@midnight.cs.hut.fi>, Nikodemus Siivola
<tsii...@kekkonen.cs.hut.fi> wrote:

> How many times have people explained this to you? I've lost count. Grahams
> book was published *before* there was an ANSI standard.

I am well aware of that. His "old" book is still quite useful for
learning purposes.

I am not at all convinced that using "undefined behavior" is as bad a
thing as some make it out to be.

After all, Paul Graham must have known that the behavior of variables
at the time of his book work was "undefined behavior", even at that
time. Despite all that, he still used "undefined behavior".

Once a programmer demonstrates to his clients that a problem is
"solvable" by using CL "behavior", undefined or otherwise, it becomes a
lot easier to gain funding for the project in order to re-code the
"bandit-Lisp" into production code that is reliable.

The clients have the priceless knowledge that their funds will not be
wasted on a project that has no chance of success, because the Lisp
version works in so far as cracking the problem is concerned.

Mark-

_ XL1201 _ Sebek _ Budo _ Kafka @hotmail.com Franz Kafka

unread,
May 8, 2003, 4:44:08 PM5/8/03
to
Mark Conrad wrote:
> In article <lyd6it6...@cartan.de>, Nils Goesche <car...@cartan.de>
> wrote:
>
> > Heh. Looks like a bug to in MCL to me.
>
> Anything is possible in that piece of code. I will take the easy way
> out and use eval-when, as long as it works:
>

If it works for your project in your Lisp that is all that really matters.

It depends on wheather or not you want to make it portable. If you are happy
with the app. running in MCL you can leave it just the way it is, even with
the 'undefined behavior' because it is working in MCL.

If some one else should want to port it to a different CL compiler thay
might have to make changes to get it to run.

However it is not wrong to relie on 'undefined behavior' -- it is the same
as reling on an implementation specific function such as streams, or a web
server.

If the code works, undefined or not, use it. :)

Seasoned Users Note:We should not try to scare a CL newbe away from the
lang. we're having enough troble attracting them to Lisp in the first place.

& what does jumping off the Brooklyn Bridge have to do with barrowing some
of Paul Garhams CL code from 'On Lisp.'

Even though commonp and define-setf-method are no longer ANSI it is not
wrong for a user to write code to implement them--in fact it could be easier
to add two functions, that it would be to rewrite all the code that depends
on them. I just chose those funcs. of the top of my head /w no rhyme or
reason.


Henrik Motakef

unread,
May 8, 2003, 5:06:03 PM5/8/03
to
"Franz Kafka" <Symbolics _ XL1201 _ Sebek _ Budo _ Kafka @ hotmail . com> writes:

> If it works for your project in your Lisp that is all that really matters.
>
> It depends on wheather or not you want to make it portable. If you are happy
> with the app. running in MCL you can leave it just the way it is, even with
> the 'undefined behavior' because it is working in MCL.

In the version of MCL he currently uses, that is. And unless he does
anything else that might cause this version to behave differently.

> Seasoned Users Note:We should not try to scare a CL newbe away from the
> lang. we're having enough troble attracting them to Lisp in the first place.

Thanks for educating us. I'm sure letting newbies run in all sorts of
needless trouble will do wonders for Lisp popularity.

Regards
Henrik

_ XL1201 _ Sebek _ Budo _ Kafka @hotmail.com Franz Kafka

unread,
May 8, 2003, 5:25:56 PM5/8/03
to

"Henrik Motakef" <henrik....@web.de> wrote in message
news:87vfwl2...@interim.henrik-motakef.de...

>
> Thanks for educating us. I'm sure letting newbies run in all sorts of
> needless trouble will do wonders for Lisp popularity.
>
> Regards
> Henrik

I think asking him if he'd jump off a bridge with Paul Garham was going a
little too far. He already decided that he's going to write his program--I
think we should help him.

a.)
Teach him about #+ #- reader macros.

b.)
Teach him how to add the feature he needs to Lisp so
it is not undefined.

c.)
Teach him how to check for the error so he can run his code.

d.)
Show him an other way to implement continuations in Lisp because
that is what he wants to do. If he knew of a better or safer way to
do it--I'm sure he would.

But it would be a waste of bandwidth to try to talk him out of doing what he
already decided he was going to do. We warned him it might be dangerous--but
he might have 2 find out 4 himself.

(Debugging the code and getting it to run might even be his best teacher.)

Someone should tell him what might work, not why his code might not--because
that would help him more

----------

#+(MCL) ;; informs user that code runs in MCL
;; but other code might be needed for other CLs.


(eval-when (:load-toplevel :execute)
(setf (symbol-value '%cont%)
(lambda (&rest args)
(if (cdr args)
args
(car args)) )))

#-(MCL) (+ 3 4) ;; does not get evaluated in MCL.

The #+ & #- macros are used to write non-portable code in
a portable way. The non-portable parts are written with the
#- or #+ reader function to make sure the right Lisp uses
the right functions.

I don't know much about #- or #+ except that thay could
be used to make your code run in all CLs. Someone on this
list might know.


Pascal Costanza

unread,
May 8, 2003, 5:57:30 PM5/8/03
to
In article <080520031323350888%nos...@iam.invalid>,
Mark Conrad <nos...@iam.invalid> wrote:

> In article <b9deds$o5m$1...@f1node01.rhrz.uni-bonn.de>, Pascal Costanza
> <cost...@web.de> wrote:
>
> > Section 1.5 of the HyperSpec tells you _exactly_ what you can and must
> > not assume with regard to portability of your programs across conforming
> > implementations. See
> > http://www.lispworks.com/reference/HyperSpec/Body/01_e.htm
>
> Do you happen to know where I can buy a hardcopy of the HyperSpec.

There are no hardcopies of the HyperSpec available. You can get
hardcopies of the ANSI spec, but they are very expensive.

> Just curious if a hardcopy is available, and where.
>
> My Mac, running OS 10.2.4 (so-called "OS X") - froze up when I was
> using the downloadable version. That is the first time in six months
> that OS X froze on anything.

I am also running OS X and don't have this problem. Just try again.

Pascal

Marc Spitzer

unread,
May 8, 2003, 6:03:28 PM5/8/03
to
Mark Conrad <nos...@iam.invalid> writes:

> In article <2003050806...@mapcar.org>, Matthew Danish
> <mda...@andrew.cmu.edu> wrote:

> > Prove me wrong.
>
> Why should I bother. That is a bunch of work.

Because this is how discussions between *adults*
work. And yes it is a lot of work to do this,
that is how knowledge is produced.

>
>
> > Or stop making broad statements about an issue which you are
> > clueless about, at least in a forum that better-informed people are
> > reading.
>
> I most certainly will not! Making those broad statements has a decided
> benefit for me. If my statement is wrong, I get ample replies
> informing me exactly how the cookie crumbles.

You do not seem to understand that the rest of us are not here
for your pleasure. You are not the center of creation and you
should not act like it

>
> From those replies, I can ignore the hate mongers, and sift out
> knowledge that is understandable to me.

At least you admit you do not understand the correct answers
that people have posted to your questions, you only understand
the answers that agree with your preconceived ideas. This is
so stupid when you consider that even you know that you do not
know what you are talking about.

>
> Why should I abandon such a good learning tool.

Because you do not learn.

>
> Other Lisp newbies won't be influenced by my remarks, because I have
> stated up front that I am a Lisp newbie also, many times.

From your observed behavior I am leaning more towards fool.

>
> My "clueless" broad remarks merely reflect the present stage of my
> understanding, which is subject to daily change and improvement.
>
> That is why I get a kick out of those guys who dig up old erroneous
> remarks of mine, that I have long since rejected as wrong, in their
> vain efforts to discredit me.

No one is trying to discredit you, you are doing an excellent job
by your self.

>
> I just ignore them, they obviously have some sort of ego thing where
> they feel the need to look clever-by-comparison to a newbie.

Well I am beginning to think my mouse pad may be smarter then you,
just because it has never talked to me.

>
> If you can't stand the heat in the "clueless" kitchen, stay out.

Do you see what happens when Erik goes away???

marc

--
who likes his 'c' more and more

Edi Weitz

unread,
May 8, 2003, 6:09:18 PM5/8/03
to
Pascal Costanza <cost...@web.de> writes:

> In article <080520031323350888%nos...@iam.invalid>,
> Mark Conrad <nos...@iam.invalid> wrote:
>
> > Do you happen to know where I can buy a hardcopy of the HyperSpec.
>
> There are no hardcopies of the HyperSpec available. You can get
> hardcopies of the ANSI spec, but they are very expensive.

You can get the Postscript files of the latest draft (which IIRC has
the same contents as the final ANSI spec and only differs with respect
to formatting) and print them yourself. See the thread "HyperSpec in
other formats" for URLs.

Or you can buy a copy of CLtL2 and "convert" it to ANSI CL:

<http://bc19191.home.attbi.com/cltl2-ansi.htm>.

(Of course this is not the same as the ANSI spec but it's a good start
and you'll most likely learn something while you do that. I'm going to
do it this weekend... :)

Edi.

Mario S. Mommer

unread,
May 8, 2003, 6:11:55 PM5/8/03
to
Marc Spitzer <mspi...@optonline.net> writes:
> >
> > If you can't stand the heat in the "clueless" kitchen, stay out.
>
> Do you see what happens when Erik goes away???

Remember Ilias? He took enormous amounts of abuse and didn't go
away. He disappeared when people stopped feeding him. If you think
flames help, go look at sci.math and witness how utterly useless they
can be.

Just
Dont Feed The Trolls!

Mario.

Daniel Barlow

unread,
May 8, 2003, 6:35:40 PM5/8/03