Hi,
It seems to me that ASSERT and CHECK-TYPE are not as convenient as they could be. In particular, ISLISP seems to have a better alternative in ASSURE.
ASSURE is easy to define:
(defmacro assure (type form) (let ((object (copy-symbol 'object))) `(let ((,object ,form)) (check-type ,object ,type) ,object)))
The important difference is that the value of form is returned, which allows using ASSURE inline in expressions:
(1+ (assure number x))
…in place of the more lengthy:
(progn (check-type x number) (1+ x))
Is ASSURE, or something similar, part of any utility library, like Alexandria or the likes?
On an unrelated note, I recently came up with the following utility macro which I found very useful:
(defmacro assocf (item alist &optional default &rest keys &key test test-not key) (declare (ignore test test-not key)) (let ((it (copy-symbol 'it)) (cons (copy-symbol 'cons))) `(let* ((,it ,item) (,cons (assoc ,it ,alist ,@keys))) (unless ,cons (setf ,cons (cons ,it ,default) ,alist (cons ,cons ,alist))) ,cons)))
Again, is something like this already part of some utility library?
Thanks, Pascal
-- Pascal Costanza The views expressed in this email are my own, and not those of my employer.
On Sun, Sep 22, 2013 at 9:53 AM, Pascal Costanza pc@p-cos.net wrote:
(defmacro assure (type form) (let ((object (copy-symbol 'object))) `(let ((,object ,form)) (check-type ,object ,type) ,object)))
If Alexandria doesn't want it, the problem is that there doesn't seem to be any widespread enough library for general utilities that moves at decent speed http://xkcd.com/927/
(defmacro assocf (item alist &optional default &rest keys &key test test-not key) (declare (ignore test test-not key)) (let ((it (copy-symbol 'it)) (cons (copy-symbol 'cons))) `(let* ((,it ,item) (,cons (assoc ,it ,alist ,@keys))) (unless ,cons (setf ,cons (cons ,it ,default) ,alist (cons ,cons ,alist))) ,cons)))
This implementation loses badly if the alist form has side-effects. That where you'd use the long form of define-modify-macro. Also, assocf is a slightly confusing name considering what you usually expect from define-modify-macro.
—♯ƒ • François-René ÐVB Rideau •Reflection&Cybernethics• http://fare.tunes.org You think you know when you can learn, are more sure when you can write, even more when you can teach, but certain when you can program. — Alan Perlis
On Sep 22, 2013, at 11:24 AM, Faré fahree@gmail.com wrote:
(defmacro assocf (item alist &optional default &rest keys &key test test-not key) …
… side-effects ...
Lispwork's has cdr-assoc, which works on places: http://www.lispworks.com/documentation/lw50/LWRM/html/lwref-618.htm
See also https://code.google.com/p/cdr-assoc/ which I wrote some years ago, and I have no memory of what it's short comings might be.
On 22 Sep 2013, at 17:24, Faré fahree@gmail.com wrote:
On Sun, Sep 22, 2013 at 9:53 AM, Pascal Costanza pc@p-cos.net wrote:
(defmacro assure (type form) (let ((object (copy-symbol 'object))) `(let ((,object ,form)) (check-type ,object ,type) ,object)))
If Alexandria doesn't want it, the problem is that there doesn't seem to be any widespread enough library for general utilities that moves at decent speed http://xkcd.com/927/
Well, I hope someone's listening. ;)
(defmacro assocf (item alist &optional default &rest keys &key test test-not key) (declare (ignore test test-not key)) (let ((it (copy-symbol 'it)) (cons (copy-symbol 'cons))) `(let* ((,it ,item) (,cons (assoc ,it ,alist ,@keys))) (unless ,cons (setf ,cons (cons ,it ,default) ,alist (cons ,cons ,alist))) ,cons)))
This implementation loses badly if the alist form has side-effects. That where you'd use the long form of define-modify-macro.
Good point. This should be better:
(defmacro assocf (item alist &optional default &rest keys &key test test-not key &environment env) (declare (ignore test test-not key)) (let ((it (copy-symbol 'it)) (cons (copy-symbol 'cons))) (multiple-value-bind (vars vals store-vars writer reader) (get-setf-expansion alist env) (assert (null (cdr store-vars))) `(let* ((,it ,item) ,@(mapcar 'list vars vals) (,cons (assoc ,it ,reader ,@keys))) (unless ,cons (setq ,cons (cons ,it ,default)) (let ((,(car store-vars) (cons ,cons ,reader))) ,writer)) ,cons))))
Also, assocf is a slightly confusing name considering what you usually expect from define-modify-macro.
I'm open for better suggestions. I chose assocf because it reminds me of getf.
Pascal
-- Pascal Costanza The views expressed in this email are my own, and not those of my employer.
As language lawyer, I must point out that the proposed definition of assure is not compatible with places that are multiple-valued. check-type is required to be (because the ANS mentions no exception about it) although I'm sure lots of implementations get this wrong.
On Sun, Sep 22, 2013 at 6:53 AM, Pascal Costanza pc@p-cos.net wrote:
Hi,
It seems to me that ASSERT and CHECK-TYPE are not as convenient as they could be. In particular, ISLISP seems to have a better alternative in ASSURE.
ASSURE is easy to define:
(defmacro assure (type form) (let ((object (copy-symbol 'object))) `(let ((,object ,form)) (check-type ,object ,type) ,object)))
The important difference is that the value of form is returned, which allows using ASSURE inline in expressions:
(1+ (assure number x))
…in place of the more lengthy:
(progn (check-type x number) (1+ x))
Is ASSURE, or something similar, part of any utility library, like Alexandria or the likes?
On an unrelated note, I recently came up with the following utility macro which I found very useful:
(defmacro assocf (item alist &optional default &rest keys &key test test-not key) (declare (ignore test test-not key)) (let ((it (copy-symbol 'it)) (cons (copy-symbol 'cons))) `(let* ((,it ,item) (,cons (assoc ,it ,alist ,@keys))) (unless ,cons (setf ,cons (cons ,it ,default) ,alist (cons ,cons ,alist))) ,cons)))
Again, is something like this already part of some utility library?
Thanks, Pascal
-- Pascal Costanza The views expressed in this email are my own, and not those of my employer.
On 22 Sep 2013, at 18:44, Steve Haflich shaflich@gmail.com wrote:
As language lawyer, I must point out that the proposed definition of assure is not compatible with places that are multiple-valued. check-type is required to be (because the ANS mentions no exception about it) although I'm sure lots of implementations get this wrong.
Another good point. However, this seems to suggest that it's not possible to implement ASSURE portably if the goal is to cover multiple values as well. Or am I missing something?
Pascal
On Sun, Sep 22, 2013 at 6:53 AM, Pascal Costanza pc@p-cos.net wrote: Hi,
It seems to me that ASSERT and CHECK-TYPE are not as convenient as they could be. In particular, ISLISP seems to have a better alternative in ASSURE.
ASSURE is easy to define:
(defmacro assure (type form) (let ((object (copy-symbol 'object))) `(let ((,object ,form)) (check-type ,object ,type) ,object)))
The important difference is that the value of form is returned, which allows using ASSURE inline in expressions:
(1+ (assure number x))
…in place of the more lengthy:
(progn (check-type x number) (1+ x))
Is ASSURE, or something similar, part of any utility library, like Alexandria or the likes?
On an unrelated note, I recently came up with the following utility macro which I found very useful:
(defmacro assocf (item alist &optional default &rest keys &key test test-not key) (declare (ignore test test-not key)) (let ((it (copy-symbol 'it)) (cons (copy-symbol 'cons))) `(let* ((,it ,item) (,cons (assoc ,it ,alist ,@keys))) (unless ,cons (setf ,cons (cons ,it ,default) ,alist (cons ,cons ,alist))) ,cons)))
Again, is something like this already part of some utility library?
Thanks, Pascal
-- Pascal Costanza The views expressed in this email are my own, and not those of my employer.
-- Pascal Costanza The views expressed in this email are my own, and not those of my employer.
See fare-utils:define-values-modify-macro
(defmacro define-values-modify-macro (name val-vars lambda-list function) "Multiple-values variant on define-modify macro, by Tim Moore" (let ((env (gensym "ENV"))) `(defmacro ,name (,@val-vars ,@lambda-list &environment ,env) (multiple-value-bind (vars vals store-vars writer-form reader-form) (get-setf-expansion `(values ,,@val-vars) ,env) (let ((val-temps (mapcar #'(lambda (temp) (gensym (symbol-name temp))) ',val-vars))) `(let* (,@(mapcar #'list vars vals) ,@store-vars) (multiple-value-bind ,val-temps ,reader-form (multiple-value-setq ,store-vars (,',function ,@val-temps ,,@lambda-list))) ,writer-form (values ,@store-vars))))))) —♯ƒ • François-René ÐVB Rideau •Reflection&Cybernethics• http://fare.tunes.org
On Sun, Sep 22, 2013 at 1:15 PM, Pascal Costanza pc@p-cos.net wrote:
On 22 Sep 2013, at 18:44, Steve Haflich shaflich@gmail.com wrote:
As language lawyer, I must point out that the proposed definition of assure is not compatible with places that are multiple-valued. check-type is required to be (because the ANS mentions no exception about it) although I'm sure lots of implementations get this wrong.
Another good point. However, this seems to suggest that it's not possible to implement ASSURE portably if the goal is to cover multiple values as well. Or am I missing something?
Pascal
On Sun, Sep 22, 2013 at 6:53 AM, Pascal Costanza pc@p-cos.net wrote:
Hi,
It seems to me that ASSERT and CHECK-TYPE are not as convenient as they could be. In particular, ISLISP seems to have a better alternative in ASSURE.
ASSURE is easy to define:
(defmacro assure (type form) (let ((object (copy-symbol 'object))) `(let ((,object ,form)) (check-type ,object ,type) ,object)))
The important difference is that the value of form is returned, which allows using ASSURE inline in expressions:
(1+ (assure number x))
…in place of the more lengthy:
(progn (check-type x number) (1+ x))
Is ASSURE, or something similar, part of any utility library, like Alexandria or the likes?
On an unrelated note, I recently came up with the following utility macro which I found very useful:
(defmacro assocf (item alist &optional default &rest keys &key test test-not key) (declare (ignore test test-not key)) (let ((it (copy-symbol 'it)) (cons (copy-symbol 'cons))) `(let* ((,it ,item) (,cons (assoc ,it ,alist ,@keys))) (unless ,cons (setf ,cons (cons ,it ,default) ,alist (cons ,cons ,alist))) ,cons)))
Again, is something like this already part of some utility library?
Thanks, Pascal
-- Pascal Costanza The views expressed in this email are my own, and not those of my employer.
-- Pascal Costanza The views expressed in this email are my own, and not those of my employer.
This seems to help if you know upfront how many values you are dealing with.
However, the parameter list of assure is (type form). To the best of my knowledge, there is no portable way to expand a type to see if it expands to a values form, which would give you chance to construct a form that knows the number of values.
Without that knowledge, you would have to construct a form that is agnostic in that regard. However:
(defmacro assure (type form) (let ((values (copy-symbol 'values))) `(let ((,values (multiple-value-list ,form))) (check-type (apply 'values ,values) ,type) (apply 'values ,values))))
This is not a portable definition, since (apply 'values …) is not a portable place.
typep also doesn't help. Any other options?
Pascal
On 22 Sep 2013, at 19:19, Faré fahree@gmail.com wrote:
See fare-utils:define-values-modify-macro
(defmacro define-values-modify-macro (name val-vars lambda-list function) "Multiple-values variant on define-modify macro, by Tim Moore" (let ((env (gensym "ENV"))) `(defmacro ,name (,@val-vars ,@lambda-list &environment ,env) (multiple-value-bind (vars vals store-vars writer-form reader-form) (get-setf-expansion `(values ,,@val-vars) ,env) (let ((val-temps (mapcar #'(lambda (temp) (gensym (symbol-name temp))) ',val-vars))) `(let* (,@(mapcar #'list vars vals) ,@store-vars) (multiple-value-bind ,val-temps ,reader-form (multiple-value-setq ,store-vars (,',function ,@val-temps ,,@lambda-list))) ,writer-form (values ,@store-vars))))))) —♯ƒ • François-René ÐVB Rideau •Reflection&Cybernethics• http://fare.tunes.org
On Sun, Sep 22, 2013 at 1:15 PM, Pascal Costanza pc@p-cos.net wrote:
On 22 Sep 2013, at 18:44, Steve Haflich shaflich@gmail.com wrote:
As language lawyer, I must point out that the proposed definition of assure is not compatible with places that are multiple-valued. check-type is required to be (because the ANS mentions no exception about it) although I'm sure lots of implementations get this wrong.
Another good point. However, this seems to suggest that it's not possible to implement ASSURE portably if the goal is to cover multiple values as well. Or am I missing something?
Pascal
On Sun, Sep 22, 2013 at 6:53 AM, Pascal Costanza pc@p-cos.net wrote:
Hi,
It seems to me that ASSERT and CHECK-TYPE are not as convenient as they could be. In particular, ISLISP seems to have a better alternative in ASSURE.
ASSURE is easy to define:
(defmacro assure (type form) (let ((object (copy-symbol 'object))) `(let ((,object ,form)) (check-type ,object ,type) ,object)))
The important difference is that the value of form is returned, which allows using ASSURE inline in expressions:
(1+ (assure number x))
…in place of the more lengthy:
(progn (check-type x number) (1+ x))
Is ASSURE, or something similar, part of any utility library, like Alexandria or the likes?
On an unrelated note, I recently came up with the following utility macro which I found very useful:
(defmacro assocf (item alist &optional default &rest keys &key test test-not key) (declare (ignore test test-not key)) (let ((it (copy-symbol 'it)) (cons (copy-symbol 'cons))) `(let* ((,it ,item) (,cons (assoc ,it ,alist ,@keys))) (unless ,cons (setf ,cons (cons ,it ,default) ,alist (cons ,cons ,alist))) ,cons)))
Again, is something like this already part of some utility library?
Thanks, Pascal
-- Pascal Costanza The views expressed in this email are my own, and not those of my employer.
-- Pascal Costanza The views expressed in this email are my own, and not those of my employer.
-- Pascal Costanza
No, it is generally possible to write portable setf expanders that work with multiple-value places provided the platform conforms to the ANS requirements. I have some extreme examples on another machine I may share to the list later.
I think to be portable transparent assure would need to collect and return multiple values, with the hope that the compiler would eliminate that stuff if the place were a single-value form like a variable or known function.
On 22 Sep 2013, at 20:45, Steve Haflich shaflich@gmail.com wrote:
No, it is generally possible to write portable setf expanders that work with multiple-value places provided the platform conforms to the ANS requirements. I have some extreme examples on another machine I may share to the list later.
I think to be portable transparent assure would need to collect and return multiple values, with the hope that the compiler would eliminate that stuff if the place were a single-value form like a variable or known function.
OK, it seems you mean something like this:
(defmacro assure (type form &environment env) (multiple-value-bind (vars vals store-vars writer reader) (get-setf-expansion ,form env) (declare (ignore store-vars writer)) `(let* ,(mapcar 'list vars vals) (check-type ,reader ,type) ,reader)))
However, this is not good enough. Something as simple as (assure integer (+ x y)) already doesn't work. The requirement that form is a generalized reference is an artifact that comes from check-type, but that shouldn't leak through.
I came up with another version. I believe this should work:
(defmacro assure (type form) (let ((values (copy-symbol 'values))) `(let ((,values (multiple-value-list ,form))) (declare (dynamic-extent values)) (etypecase (values-list ,values) (,type (values-list ,values))))))
…except that this also doesn't work in some Common Lisp implementations for multiple values, but I think it should and those implementations need to be fixed.
Pascal
-- Pascal Costanza The views expressed in this email are my own, and not those of my employer.
It's sad that this conses...
On Sun, Sep 22, 2013 at 3:44 PM, Pascal Costanza pc@p-cos.net wrote:
On 22 Sep 2013, at 20:45, Steve Haflich shaflich@gmail.com wrote:
No, it is generally possible to write portable setf expanders that work with multiple-value places provided the platform conforms to the ANS requirements. I have some extreme examples on another machine I may share to the list later.
I think to be portable transparent assure would need to collect and return multiple values, with the hope that the compiler would eliminate that stuff if the place were a single-value form like a variable or known function.
OK, it seems you mean something like this:
(defmacro assure (type form &environment env) (multiple-value-bind (vars vals store-vars writer reader) (get-setf-expansion ,form env) (declare (ignore store-vars writer)) `(let* ,(mapcar 'list vars vals) (check-type ,reader ,type) ,reader)))
However, this is not good enough. Something as simple as (assure integer (+ x y)) already doesn't work. The requirement that form is a generalized reference is an artifact that comes from check-type, but that shouldn't leak through.
I came up with another version. I believe this should work:
(defmacro assure (type form) (let ((values (copy-symbol 'values))) `(let ((,values (multiple-value-list ,form))) (declare (dynamic-extent values)) (etypecase (values-list ,values) (,type (values-list ,values))))))
…except that this also doesn't work in some Common Lisp implementations for multiple values, but I think it should and those implementations need to be fixed.
Pascal
-- Pascal Costanza The views expressed in this email are my own, and not those of my employer.
On 22 Sep 2013, at 22:18, Scott McKay swmckay@gmail.com wrote:
It's sad that this conses…
True. I think I will use the single-value version for my own purposes. If this were to become part of a utilities library, it should probably best be split into a single-value ASSURE and a MULTIPLE-VALUE-ASSURE for multiple values, so you only pay for the overhead when you actually need it.
Pascal
On Sun, Sep 22, 2013 at 3:44 PM, Pascal Costanza pc@p-cos.net wrote:
On 22 Sep 2013, at 20:45, Steve Haflich shaflich@gmail.com wrote:
No, it is generally possible to write portable setf expanders that work with multiple-value places provided the platform conforms to the ANS requirements. I have some extreme examples on another machine I may share to the list later.
I think to be portable transparent assure would need to collect and return multiple values, with the hope that the compiler would eliminate that stuff if the place were a single-value form like a variable or known function.
OK, it seems you mean something like this:
(defmacro assure (type form &environment env) (multiple-value-bind (vars vals store-vars writer reader) (get-setf-expansion ,form env) (declare (ignore store-vars writer)) `(let* ,(mapcar 'list vars vals) (check-type ,reader ,type) ,reader)))
However, this is not good enough. Something as simple as (assure integer (+ x y)) already doesn't work. The requirement that form is a generalized reference is an artifact that comes from check-type, but that shouldn't leak through.
I came up with another version. I believe this should work:
(defmacro assure (type form) (let ((values (copy-symbol 'values))) `(let ((,values (multiple-value-list ,form))) (declare (dynamic-extent values)) (etypecase (values-list ,values) (,type (values-list ,values))))))
…except that this also doesn't work in some Common Lisp implementations for multiple values, but I think it should and those implementations need to be fixed.
Pascal
-- Pascal Costanza The views expressed in this email are my own, and not those of my employer.
-- Pascal Costanza The views expressed in this email are my own, and not those of my employer.
On Sun, Sep 22, 2013 at 1:18 PM, Scott McKay swmckay@gmail.com wrote:
It's sad that this conses...
A challenge exercise for students:
If an implementation can stack-cons a &rest list, no heap consing is necessary.
Hint: multiple-value-call
Hmmm, I notice the ANS says this about the VALUES type specifier:
This *type specifier*http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_t.htm#type_specifier can be used only as the *value-type* in a *function*http://www.lispworks.com/documentation/HyperSpec/Body/t_fn.htm#function *type specifier*http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_t.htm#type_specifier or a *the*http://www.lispworks.com/documentation/HyperSpec/Body/s_the.htm#the *special form*http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_s.htm#special_form .
I consider this to be a flaw in the ANS. The CHECK-TYPE macro takes a _place_ as its first subform, and _place_ is defined in the glossary in terms of _generalized reference_ which in 5.1.1 contains text mentioning values plural in a couple places, e.g.
the ultimate result of evaluating *setf*http://www.franz.com/support/documentation/current/ansicl/dictentr/setfpset.htm is the value or values being stored.
I think during the proofreading of the many ANS drafts no one except me ever checked this issue for consistency, and I did it 21 years too late.
If god had intended standards to be such precious things, he wouldn't have made so many of them.
On Sun, Sep 22, 2013 at 5:45 PM, Steve Haflich shaflich@gmail.com wrote:
On Sun, Sep 22, 2013 at 1:18 PM, Scott McKay swmckay@gmail.com wrote:
It's sad that this conses...
A challenge exercise for students:
If an implementation can stack-cons a &rest list, no heap consing is necessary.
Hint: multiple-value-call
ccl has a function (not a macro) called require-type, as in (1+ (require-type x 'number)). Very useful indeed.
On Sun, Sep 22, 2013 at 9:53 AM, Pascal Costanza pc@p-cos.net wrote:
Hi,
It seems to me that ASSERT and CHECK-TYPE are not as convenient as they could be. In particular, ISLISP seems to have a better alternative in ASSURE.
ASSURE is easy to define:
(defmacro assure (type form) (let ((object (copy-symbol 'object))) `(let ((,object ,form)) (check-type ,object ,type) ,object)))
The important difference is that the value of form is returned, which allows using ASSURE inline in expressions:
(1+ (assure number x))
…in place of the more lengthy:
(progn (check-type x number) (1+ x))
Is ASSURE, or something similar, part of any utility library, like Alexandria or the likes?
On an unrelated note, I recently came up with the following utility macro which I found very useful:
(defmacro assocf (item alist &optional default &rest keys &key test test-not key) (declare (ignore test test-not key)) (let ((it (copy-symbol 'it)) (cons (copy-symbol 'cons))) `(let* ((,it ,item) (,cons (assoc ,it ,alist ,@keys))) (unless ,cons (setf ,cons (cons ,it ,default) ,alist (cons ,cons ,alist))) ,cons)))
Again, is something like this already part of some utility library?
Thanks, Pascal
-- Pascal Costanza The views expressed in this email are my own, and not those of my employer.