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)))))))
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.
Another variant:
(defun specialp (symbol)
(let ((unique (gensym)))
(eval `(let ((,symbol ',unique))
(when (boundp ',symbol)
(eq (symbol-value ',symbol) ',unique))))))
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))
> 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
> 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
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).
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)))))))))
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 {}.
---------------------------------------------------------------------------
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.
(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
> 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.
>> 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.
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.
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
Sorry for the late reply. This same question was asked at least once
before.
-Jason