Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

portable detection of special symbols?

30 views
Skip to first unread message

D Herring

unread,
Apr 23, 2011, 3:07:36 PM4/23/11
to
Special Operator SYMBOL-MACROLET:
"symbol-macrolet signals an error if a special declaration names one
of the symbols being defined by symbol-macrolet"

Is there a better way not requiring the cltl2 environment interface?

Thanks,
Daniel

Pascal Costanza

unread,
Apr 23, 2011, 4:31:35 PM4/23/11
to

(defun specialp (symbol)
(eval `(let ((,symbol 0))
(zerop (funcall (let ((,symbol 1))
(lambda () ,symbol)))))))


Pascal

--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
The views expressed are my own, and not those of my employer.

Pascal Costanza

unread,
Apr 23, 2011, 4:35:41 PM4/23/11
to
On 23/04/2011 21:07, D Herring wrote:

Another variant:

(defun specialp (symbol)
(let ((unique (gensym)))
(eval `(let ((,symbol ',unique))
(when (boundp ',symbol)
(eq (symbol-value ',symbol) ',unique))))))

Pascal Costanza

unread,
Apr 23, 2011, 4:46:23 PM4/23/11
to
On 23/04/2011 22:31, Pascal Costanza wrote:
> On 23/04/2011 21:07, D Herring wrote:
>> Special Operator SYMBOL-MACROLET:
>> "symbol-macrolet signals an error if a special declaration names one of
>> the symbols being defined by symbol-macrolet"
>>
>> Is there a better way not requiring the cltl2 environment interface?
>>
>> Thanks,
>> Daniel
>
> (defun specialp (symbol)
> (eval `(let ((,symbol 0))
> (zerop (funcall (let ((,symbol 1))
> (lambda () ,symbol)))))))

The following is a variant that moves some code out of the part
evaluated at runtime:

(defun specialp (symbol)
(progv (list symbol) '(0)
(zerop (funcall (eval `(let ((,symbol 1))

RG

unread,
Apr 23, 2011, 5:00:24 PM4/23/11
to
In article <91grgt...@mid.individual.net>,
Pascal Costanza <p...@p-cos.net> wrote:

> On 23/04/2011 21:07, D Herring wrote:
> > Special Operator SYMBOL-MACROLET:
> > "symbol-macrolet signals an error if a special declaration names one of
> > the symbols being defined by symbol-macrolet"
> >
> > Is there a better way not requiring the cltl2 environment interface?
> >
> > Thanks,
> > Daniel
>
> Another variant:
>
> (defun specialp (symbol)
> (let ((unique (gensym)))
> (eval `(let ((,symbol ',unique))
> (when (boundp ',symbol)
> (eq (symbol-value ',symbol) ',unique))))))
>
>
> Pascal

Doesn't work:

? (defconstant x 1)
X
? (specialp 'x)
> Error: While compiling an anonymous function :
> Can't bind or assign to constant X., in process Listener(8).

rg

RG

unread,
Apr 23, 2011, 5:01:17 PM4/23/11
to
In article <91gs4v...@mid.individual.net>,
Pascal Costanza <p...@p-cos.net> wrote:

> On 23/04/2011 22:31, Pascal Costanza wrote:
> > On 23/04/2011 21:07, D Herring wrote:
> >> Special Operator SYMBOL-MACROLET:
> >> "symbol-macrolet signals an error if a special declaration names one of
> >> the symbols being defined by symbol-macrolet"
> >>
> >> Is there a better way not requiring the cltl2 environment interface?
> >>
> >> Thanks,
> >> Daniel
> >
> > (defun specialp (symbol)
> > (eval `(let ((,symbol 0))
> > (zerop (funcall (let ((,symbol 1))
> > (lambda () ,symbol)))))))
>
> The following is a variant that moves some code out of the part
> evaluated at runtime:
>
> (defun specialp (symbol)
> (progv (list symbol) '(0)
> (zerop (funcall (eval `(let ((,symbol 1))
> (lambda () ,symbol)))))))
>
>
>
> Pascal

Doesn't work:

? (defconstant x 1)
X

? (defun specialp (symbol)


(progv (list symbol) '(0)
(zerop (funcall (eval `(let ((,symbol 1))
(lambda () ,symbol)))))))

SPECIALP
? (specialp 'x)
> Error: (X) is not a proper list of bindable symbols of length < 169.

rg

Tim Bradshaw

unread,
Apr 23, 2011, 6:00:58 PM4/23/11
to
On 2011-04-23 22:00:24 +0100, RG said:
>
> Doesn't work:

I'm not sure this is correct but: can something be BOUNDP and not
CONSTANTP and *not* a special variable? That would still miss things
which were declared special but not bound (and symbol macros would just
be death).

Pascal Costanza

unread,
Apr 23, 2011, 6:29:05 PM4/23/11
to

This doesn't take that much creativity:

(defun specialp (symbol)
(values
(ignore-errors


(progv (list symbol) '(0)
(zerop (funcall (eval `(let ((,symbol 1))

(lambda () ,symbol)))))))))

Pascal J. Bourguignon

unread,
Apr 23, 2011, 9:11:18 PM4/23/11
to
RG <rNOS...@flownet.com> writes:

I published a correct version this week in:
Message-ID: <8762q7i...@kuiper.lan.informatimago.com>


--
__Pascal Bourguignon__ http://www.informatimago.com/
A bad day in () is better than a good day in {}.

TheFlyingDutchman

unread,
Apr 23, 2011, 9:43:12 PM4/23/11
to
On Apr 23, 6:11 pm, "Pascal J. Bourguignon" <p...@informatimago.com>
wrote:
> RG <rNOSPA...@flownet.com> writes:
> > In article <91gs4vF3h...@mid.individual.net>,
Newsgroups: comp.lang.lisp
From: "Pascal J. Bourguignon" <p...@informatimago.com>
Date: Thu, 21 Apr 2011 20:33:13 +0200
Local: Thurs, Apr 21 2011 11:33 am
Subject: Re: flet vars


---------------------------------------------------------------------------


There isn't even an API to know if a symbol has been declared
special.
But we can detect it:

(defun specialp (symbol)
"Detects whether the symbol has been declared special."
(eval `(flet ((f () ,symbol)) (let ((,symbol t)) (not (nth-value 1
(ignore-errors (f))))))))


(defvar a 1)


(values
(funcall (compile nil (lambda ()
(let ((b 1))
(declare (special b))
(list (specialp 'a) (specialp 'b) (specialp
'c))))))
(list (specialp 'a) (specialp 'b) (specialp 'c)))


--> (T T NIL)
(T NIL NIL)


SPECIAL-ness is a dynamic property, in the global environment.

D Herring

unread,
Apr 23, 2011, 11:25:13 PM4/23/11
to
On 04/23/2011 09:11 PM, Pascal J. Bourguignon wrote:
> RG<rNOS...@flownet.com> writes:
>
>> In article<91gs4v...@mid.individual.net>,
>> Pascal Costanza<p...@p-cos.net> wrote:
>>
>>> On 23/04/2011 22:31, Pascal Costanza wrote:
>>>> On 23/04/2011 21:07, D Herring wrote:
>>>>> Special Operator SYMBOL-MACROLET:
>>>>> "symbol-macrolet signals an error if a special declaration names one of
>>>>> the symbols being defined by symbol-macrolet"
>>>>>
>>>>> Is there a better way not requiring the cltl2 environment interface?
...

> I published a correct version this week in:
> Message-ID:<8762q7i...@kuiper.lan.informatimago.com>

(defun specialp (symbol)


"Detects whether the symbol has been declared special."
(eval `(flet ((f () ,symbol)) (let ((,symbol t)) (not (nth-value 1
(ignore-errors (f))))))))

Thanks for the code, but I accidentally broke it on my first attempted
use in SBCL. (specialp '*readtable*) That also breaks PC's latest
solution.

Since there doesn't seem to be a gold standard, I throw in my own
lightly-tested solution.

(defun specialp (var)
(unless (constantp var)
(not (ignore-errors
(eval `(let (,var)
(symbol-macrolet ((,var 0))
t)))))))

Note that all of these will fail in the following situation, since
eval uses the null lexical environment...

(let ((potato 4))
(declare (special potato))
(specialp 'potato))

- Daniel

Pascal J. Bourguignon

unread,
Apr 24, 2011, 2:12:03 AM4/24/11
to
D Herring <dher...@at.tentpost.dot.com> writes:

> On 04/23/2011 09:11 PM, Pascal J. Bourguignon wrote:
>> RG<rNOS...@flownet.com> writes:
>>
>>> In article<91gs4v...@mid.individual.net>,
>>> Pascal Costanza<p...@p-cos.net> wrote:
>>>
>>>> On 23/04/2011 22:31, Pascal Costanza wrote:
>>>>> On 23/04/2011 21:07, D Herring wrote:
>>>>>> Special Operator SYMBOL-MACROLET:
>>>>>> "symbol-macrolet signals an error if a special declaration names one of
>>>>>> the symbols being defined by symbol-macrolet"
>>>>>>
>>>>>> Is there a better way not requiring the cltl2 environment interface?
> ...
>> I published a correct version this week in:
>> Message-ID:<8762q7i...@kuiper.lan.informatimago.com>
>
> (defun specialp (symbol)
> "Detects whether the symbol has been declared special."
> (eval `(flet ((f () ,symbol)) (let ((,symbol t)) (not (nth-value 1
> (ignore-errors (f))))))))
>
> Thanks for the code, but I accidentally broke it on my first attempted
> use in SBCL. (specialp '*readtable*) That also breaks PC's latest
> solution.

It seems to me that SBCL is not conformant on this.

Types of values must not checked at compilation time, but at run-time,
when they're used, IF they're used, and as they're used.

Pascal J. Bourguignon

unread,
Apr 24, 2011, 2:15:31 AM4/24/11
to
D Herring <dher...@at.tentpost.dot.com> writes:

>> I published a correct version this week in:
>> Message-ID:<8762q7i...@kuiper.lan.informatimago.com>
>
> (defun specialp (symbol)
> "Detects whether the symbol has been declared special."
> (eval `(flet ((f () ,symbol)) (let ((,symbol t)) (not (nth-value 1
> (ignore-errors (f))))))))
>

> [...]


> Note that all of these will fail in the following situation, since
> eval uses the null lexical environment...
>
> (let ((potato 4))
> (declare (special potato))
> (specialp 'potato))

My function doesn't fail in this case.

(let ((potato 4))
(declare (special potato))
(specialp 'potato))

--> T

and even sbcl is able to return it.

Pascal J. Bourguignon

unread,
Apr 24, 2011, 2:33:53 AM4/24/11
to
D Herring <dher...@at.tentpost.dot.com> writes:


So far, we have:


(defun specialp (symbol)
"Detects whether the symbol has been declared special."

(and (symbolp symbol)
(cond
((constantp symbol) nil)
((not (eql symbol (macroexpand symbol))) nil)
(t (handler-bind ((warning (function muffle-warning)))


(eval `(flet ((f () ,symbol))
(let ((,symbol t))

(not (nth-value 1 (ignore-errors (f))))))))))))

(defvar a 1)
(defconstant c 2)
(define-symbol-macro sa a)
(define-symbol-macro sb b)
(define-symbol-macro sc c)
(define-symbol-macro sd d)
(define-symbol-macro se 42)

(values
(funcall (compile nil (lambda ()
(let ((b 1))
(declare (special b))
(list (specialp 'a) (specialp 'b)

(specialp 'c) (specialp 'd)
(specialp 'sa) (specialp 'sb)
(specialp 'sc) (specialp 'sd)
(specialp 'se))))))


(list (specialp 'a) (specialp 'b)

(specialp 'c) (specialp 'd)
(specialp 'sa) (specialp 'sb)
(specialp 'sc) (specialp 'sd)
(specialp 'se)))

;; (T T NIL NIL NIL NIL NIL NIL NIL)
;; (T NIL NIL NIL NIL NIL NIL NIL NIL)


I claim that SPECIALP is conforming, and any implementation not giving
the same results on any symbol is not conforming.

RG

unread,
Apr 24, 2011, 3:29:15 AM4/24/11
to
In article <87zkngf...@kuiper.lan.informatimago.com>,

"Pascal J. Bourguignon" <p...@informatimago.com> wrote:

Then CCL, CLisp and SBCL are all non-conforming:

Welcome to Clozure Common Lisp Version 1.7-dev-r14715M-trunk
(DarwinX8664)!
? (defun specialp (symbol)


"Detects whether the symbol has been declared special."
(and (symbolp symbol)
(cond
((constantp symbol) nil)
((not (eql symbol (macroexpand symbol))) nil)
(t (handler-bind ((warning (function muffle-warning)))
(eval `(flet ((f () ,symbol))
(let ((,symbol t))
(not (nth-value 1 (ignore-errors (f))))))))))))

SPECIALP
? (setf (symbol-value 'x) 1)
1
? (specialp 'x)
T
? (flet ((f () x)) (let ((x 2)) (f)))
;Compiler warnings :
; In F inside an anonymous lambda form: Undeclared free variable X
; In an anonymous lambda form at position 17: Unused lexical variable X
1


I won't bother to post the transcripts from CLisp and SBCL, the results
are the same.

rg

Jason Cornez

unread,
Apr 26, 2011, 3:54:08 AM4/26/11
to
D Herring <dher...@at.tentpost.dot.com> writes:

Sorry for the late reply. This same question was asked at least once
before.

http://groups.google.com/group/comp.lang.lisp/browse_thread/thread/9df7348af59a8958/adf26e13c400c075?lnk=gst

-Jason

0 new messages