How should PROGV behave when, in the list of symbols to be bound, a
symbol is repeated twice? e.g. I get this for both ACL and SBCL -
(progv '(*x *x) '(2 3)
(symbol-value '*x))
=>
3
From the hyperspec[1], its not clear (atleast to me!) whether this
behaviour is gauranteed. Can I rely on the above result as standard
behaviour for PROGV?
Thanks,
Chaitanya
Notes -
1. http://www.lispworks.com/documentation/HyperSpec/Body/s_progv.htm#progv
On Jun 18, 12:49 pm, Chaitanya Gupta <····@chaitanyagupta.com> wrote:
> How should PROGV behave when, in the list of symbols to be bound, a
> symbol is repeated twice? e.g. I get this for both ACL and SBCL -
> (progv '(*x *x) '(2 3)
> (symbol-value '*x))
> =>
> 3
LispWorks and CLisp also return 3.
> From the hyperspec[1], its not clear (atleast to me!) whether this
> behaviour is gauranteed.
I interpret the "evaluated in order" language in the spec to mean that
the behavior is guaranteed, but I could be wrong.
Cheers,
Pillsy
Pillsy <·········@gmail.com> writes:
> On Jun 18, 12:49 pm, Chaitanya Gupta <····@chaitanyagupta.com> wrote:
>
> > How should PROGV behave when, in the list of symbols to be bound, a
> > symbol is repeated twice? e.g. I get this for both ACL and SBCL -
>
> > (progv '(*x *x) '(2 3)
> > (symbol-value '*x))
> > =>
> > 3
>
> LispWorks and CLisp also return 3.
>
> > From the hyperspec[1], its not clear (atleast to me!) whether this
> > behaviour is gauranteed.
>
> I interpret the "evaluated in order" language in the spec to mean that
> the behavior is guaranteed, but I could be wrong.
Yeah, it's probably not well-defined, which probably means it wasn't
well-defined under CLTL and earlier specs either.
If you're a pragmatist: The most likely implementations will be to
either push all the locations and then push all the values, or to push
a location then set the location in interleaved fashion. The
likelihood of someone returning 2 there is pretty low, IMO. So you
could do something at toplevel like:
(eval-when (:compile-toplevel)
(unless (eql (ignore-errors (progv '(*x *x) '(2 3)
(symbol-value '*x)))
3)
(error "Assumption about *progv violated. Need to recode.")))
Or you could ask each vendor if it's reliable and then instead of checking
at load time you could do:
#+(or vendor-a-who-says-it-is-ok vendor-b-who-says-it-is-ok)
(... do what you want ...)
#-(or vendor-a-who-says-it-is-ok vendor-b-who-says-it-is-ok)
(error "need an implementation")
Or, you could, of course, write the obvious progv* that turned into a
cascade of progv's, and then it would be well-defined what happens.
But ...
Is it out of bounds to ask why this issue comes up and whether there
might not be another answer? Like, for example, "don't allow the
situation to arise in the first place"? That's often the most elegant
answer for things like this.
Kent M Pitman wrote:
>
> Is it out of bounds to ask why this issue comes up and whether there
> might not be another answer? Like, for example, "don't allow the
> situation to arise in the first place"? That's often the most elegant
> answer for things like this.
Yes. That's probably the right thing to do. I will write what I had in
mind, and how this issue might have come up -
Say you want to create a new process and establish some dynamics
bindings for it from the parent process. So I have something like this -
(defvar *process-inherited-bindings* nil)
(defun call-with-bindings (function args &key process-bindings)
"Binds *PROCESS-INHERITED-BINDINGS* to the value of PROCESS-BINDINGS,
creates dynamic bindings from this value, and calls the FUNCTION with
ARGS inside these bindings."
(let ((*process-inherited-bindings* process-bindings))
(progv (mapcar #'car process-bindings)
(mapcar #'cdr process-bindings)
(multiple-value-list (apply function args)))))
So I can create a new process like this -
;; Using ACL's process-run-function
(mp:process-run-function "some process"
#'(lambda (bindings)
(call-with-bindings function args :process-bindings bindings))
'((*x . 1)
(*y . 2)))
The purpose of *process-inherited-bindings* is that the new process may
create another child process, and would want this new process to inherit
its bindings. i.e. inside "some process"
(mp:process-run-function "some new process"
#'(lambda (bindings)
(call-with-bindings function args :process-bindings bindings))
*process-inherited-bindings*)
Everything is fine uptil now, but say that "some process" wants *x for
"some new process" to be different from what it inherited, and leave all
the other inherited bindings intact. So what I wanted to know was
whether I could rely on this -
(mp:process-run-function "some new process"
#'(lambda (bindings)
(call-with-bindings function args :process-bindings bindings))
(cons '(*x . 2) *process-inherited-bindings*))
or this -
(mp:process-run-function "some new process"
#'(lambda (bindings)
(call-with-bindings function args :process-bindings bindings))
(append *process-inherited-bindings* '((*x . 2))))
Or whether I should always do something like this -
(mp:process-run-function "some new process"
#'(lambda (bindings)
(call-with-bindings function args :process-bindings bindings))
(remove-duplicate-bindings '((*x . 2)) *process-inherited-bindings*))
I think I have my answer now. Or is there a better way still?
(On a side note: I wanted to do this for ACL, because I didn't think it
had something like *process-inherited-bindings*. But going throught the
docs again, I found that it does give the initial bindings for a process
using mp:process-initial-bindings (provided you create them using
process-run-function's binding mechanism). So I won't really be using
this now, but it might be useful in SBCL, which AFAIK doesn't give you
the initial bindings for a process.)
Chaitanya
Chaitanya Gupta <····@chaitanyagupta.com> writes:
> Or whether I should always do something like this -
>
> (mp:process-run-function "some new process"
> #'(lambda (bindings)
> (call-with-bindings function args :process-bindings bindings))
> (remove-duplicate-bindings '((*x . 2)) *process-inherited-bindings*))
>
Perhaps
(defun call-with-bindings (function &optional bindings inherited-bindings)
(progw inherited-bindings
(progw bindings
(funcall function))))
for a suitably defined PROGW. That is, you don't really need to
remove duplicates, you could just cascade it in two calls and
would probably be fine.
I think the Lisp Machine had progw. I don't have a manual handy, so I
could not tell you for sure, but I suspect it took a list-style (rather
than cons-style alist), so it looked like a binding list. I don't recall
if it evaluated the value part, but probably not. That is, it was
probably
(progw bindings (f))
==>
(let ((temp bindings))
(progv (mapcar #'first temp)
(mapcar #'second temp)
(f)))
but maybe someone with a Chinual or some such document handy can answer.
The reason I like this is that it reflects the structure of your programs.
> I think I have my answer now. Or is there a better way still?
It's all fairly subjective. It's always good to have options.
Kent M Pitman wrote:
> Chaitanya Gupta <····@chaitanyagupta.com> writes:
>
>> Or whether I should always do something like this -
>>
>> (mp:process-run-function "some new process"
>> #'(lambda (bindings)
>> (call-with-bindings function args :process-bindings bindings))
>> (remove-duplicate-bindings '((*x . 2)) *process-inherited-bindings*))
>>
>
> Perhaps
>
> (defun call-with-bindings (function &optional bindings inherited-bindings)
> (progw inherited-bindings
> (progw bindings
> (funcall function))))
>
> for a suitably defined PROGW. That is, you don't really need to
> remove duplicates, you could just cascade it in two calls and
> would probably be fine.
>
Hmm.. Cascading progv/w(s). Didn't really think about it (even though
you mentioned it in your previous post). This should work very nicely.
>
> It's all fairly subjective. It's always good to have options.
I'll agree. Though sometimes too many options confuse me, its still
better than no options. ;)
Chaitanya
Chaitanya Gupta <····@chaitanyagupta.com> wrote:
+---------------
| (On a side note: I wanted to do this for ACL, because I didn't think it
| had something like *process-inherited-bindings*. But going throught the
| docs again, I found that it does give the initial bindings for a process
| using mp:process-initial-bindings (provided you create them using
| process-run-function's binding mechanism). So I won't really be using
| this now, but it might be useful in SBCL, which AFAIK doesn't give you
| the initial bindings for a process.)
+---------------
If they haven't changed SBCL's MP package *too* much from what
they inherited from CMUCL, there should be an :INITIAL-BINDINGS
keyword in the MP:MAKE-PROCESS function:
:INITIAL-BINDINGS
An alist of initial special bindings for the process. At
startup the new process has a fresh set of special bindings
with a default binding of *package* setup to the CL-USER
package. INITIAL-BINDINGS specifies additional bindings for
the process. The cdr of each alist element is evaluated in
the fresh dynamic environment and then bound to the car of the
element.
-Rob
-----
Rob Warnock <····@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607
Chaitanya Gupta wrote:
> Or whether I should always do something like this -
>
> (mp:process-run-function "some new process"
> #'(lambda (bindings)
> (call-with-bindings function args :process-bindings bindings))
> (remove-duplicate-bindings '((*x . 2)) *process-inherited-bindings*))
>
>
> I think I have my answer now. Or is there a better way still?
(cons '(*x . 2) (remove '*x *process-inherited-bindings* :key #'car))
Also possible:
(defun call-with-bindings (function args &key process-bindings)
(if process-bindings
(progv (list (caar process-bindings))
(list (cdar process-bindings))
(call-with-bindings function args
:process-bindings (cdr process-bindings)))
(apply function args)))
...but if *process-inherited-bindings* is a long list, this may cons too
much.
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/
Chaitanya Gupta wrote:
> How should PROGV behave when, in the list of symbols to be bound, a
> symbol is repeated twice? e.g. I get this for both ACL and SBCL -
>
> (progv '(*x *x) '(2 3)
> (symbol-value '*x))
> =>
> 3
>
> From the hyperspec[1], its not clear (atleast to me!) whether this
> behaviour is gauranteed. Can I rely on the above result as standard
> behaviour for PROGV?
No, it's simply not specified. (It's also not specified for let, lambda
and other binding forms.)
You have to preprocess the lists to ensure reliable behavior.
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/
On Mon, 18 Jun 2007 20:54:54 +0200, Pascal Costanza <··@p-cos.net> said:
| Chaitanya Gupta wrote:
|| How should PROGV behave when, in the list of symbols to be bound, a
|| symbol is repeated twice?
|| ...
| No, it's simply not specified. (It's also not specified for let,
| lambda and other binding forms.)
I. Hmmm... Which of the two options below is the right one?
I.1. Error.
In the HyperSpec, 3.1.1 Introduction to Environments [1] says:
A single name can simultaneously have more than one associated
binding per environment, but can have only one associated binding
per namespace.
Doesn't that mean that duplicating a variable is not allowed? (Or
am I reading more into it than it says? Or is it ambiguous?)
So, in I.1. I believe that duplicate symbols in the value of PROGV's
first subform (should be construed to) have undefined consequences.
I.2. Rightmost occurrence prevails.
This is based on the traditional interpretation of <lambda>xy.E as
<lambda>x.<lambda>y.E (which makes <lambda>xx.E well-defined, though
perhaps not very interestingly so).
This seems to be upheld by the following fragment from CLtL (Chapter
3, p. 38, 3rd paragraph):
If two entities have the same name, then the second may shadow the
first, in which case an occurrence of the name will refer to the
second and cannot refer to the first.
Again, I am not really sure if the above applies to the case at
hand, especially given the presence of "may". I could not find a
corresponding fragment in the HyperSpec.
II. More trouble.
For consistency's sake (at least), variable binding and function
binding should work along the same lines in the case of duplicated
names. However...
* (defun foo () (flet ((bar () 'bar1) (bar () 'bar2)) (bar)))
FOO
* (foo)
BAR2 ;so far, so good (?)
* (compile 'foo)
FOO ;
NIL ;
NIL
* (foo)
BAR1 ;hmmm...
(this is with CLisp 2.41, but that's just because that is what I
happen to have at hand right now). Is the above in error, or is it
all right since everything is all right when the consequences are
undefined?
[1] http://www.lisp.org/HyperSpec/Body/sec_3-1-1.html
---Vassil,
perplexed...
--
The truly good code is the obviously correct code.
Vassil Nikolov wrote:
> On Mon, 18 Jun 2007 20:54:54 +0200, Pascal Costanza <··@p-cos.net> said:
>
> | Chaitanya Gupta wrote:
> || How should PROGV behave when, in the list of symbols to be bound, a
> || symbol is repeated twice?
> || ...
> | No, it's simply not specified. (It's also not specified for let,
> | lambda and other binding forms.)
>
> I. Hmmm... Which of the two options below is the right one?
>
> I.1. Error.
>
> In the HyperSpec, 3.1.1 Introduction to Environments [1] says:
>
> A single name can simultaneously have more than one associated
> binding per environment, but can have only one associated binding
> per namespace.
>
> Doesn't that mean that duplicating a variable is not allowed? (Or
> am I reading more into it than it says? Or is it ambiguous?)
>
> So, in I.1. I believe that duplicate symbols in the value of PROGV's
> first subform (should be construed to) have undefined consequences.
>
> I.2. Rightmost occurrence prevails.
>
> This is based on the traditional interpretation of <lambda>xy.E as
> <lambda>x.<lambda>y.E (which makes <lambda>xx.E well-defined, though
> perhaps not very interestingly so).
>
> This seems to be upheld by the following fragment from CLtL (Chapter
> 3, p. 38, 3rd paragraph):
>
> If two entities have the same name, then the second may shadow the
> first, in which case an occurrence of the name will refer to the
> second and cannot refer to the first.
>
> Again, I am not really sure if the above applies to the case at
> hand, especially given the presence of "may". I could not find a
> corresponding fragment in the HyperSpec.
>
>
> II. More trouble.
>
> For consistency's sake (at least), variable binding and function
> binding should work along the same lines in the case of duplicated
> names. However...
>
> * (defun foo () (flet ((bar () 'bar1) (bar () 'bar2)) (bar)))
> FOO
> * (foo)
> BAR2 ;so far, so good (?)
> * (compile 'foo)
> FOO ;
> NIL ;
> NIL
> * (foo)
> BAR1 ;hmmm...
More confusion. But very interesting. Thanks for pointing these out.
Chaitanya