Le 21/02/2024 à 22:10, Marco Antoniotti a écrit :
HiI just stumbled upon this and I need confirmation. You cannot do anything like this, can you? *(defstruct foo x)* * * *(deftype foo-with-x (x) (satisfies 'foo-with-x-p)) ; No `x'!
deftype is like defmacro really. So you could write: (deftype foo-with-x (x) `(satisfies ',(intern (format nil "FOO-WITH-~S-P" x)))But you would need to have defined also the predicate with the same name at compilation-time (or, when the type is used).
cl-user> (deftype foo-with-x (x)`(satisfies ,(intern (with-standard-io-syntax (format nil "FOO-WITH-~S-P" x)))))
FOO-WITH-X cl-user> (defstruct foo x) FOO cl-user> (defstruct bar y) BAR cl-user> (defun foo-with-x-p (o) (typep o 'foo)) FOO-WITH-X-P cl-user> (defun foo-with-y-p (o) (typep o 'bar)) FOO-WITH-Y-P cl-user> (typep (make-foo) '(foo-with-x x)) T cl-user> (typep (make-foo) '(foo-with-x y)) NIL cl-user> (typep (make-bar) '(foo-with-x y)) T cl-user> (typep (make-bar) '(foo-with-x x)) NIL cl-user>
*(typep (make-foo :x 42) '(foo-with-x 42))* I.e., there is no way to pass the *x* to *foo-with-x-p*, is there?
Nope. foo-with-x-p ie. the function given to satisfies must be the name of a predicate of the whole object.
For something like: (typep (make-foo :x 42) '(foo-with-x 42)) you'd have to do: cl-user> (deftype foo-with-x (value)`(satisfies ,(intern (with-standard-io-syntax (format nil "FOO-WITH-X=~S-P" value)))))
FOO-WITH-X cl-user> (defun foo-with-x=42-p (s) (= (foo-x s) 42)) FOO-WITH-X=42-P cl-user> (typep (make-foo :x 42) '(foo-with-x 42)) T cl-user> (typep (make-foo :x 33) '(foo-with-x 42)) NIL cl-user>Of course, what we'd want, is to generate the function or closure when the deftype is expanded. This is difficult, since we need to provide satisfies a function name, and it must be defined at compilation-time.
I had a CLRFI that proposed to have lambda in satisfies, and that shows an example of what has to be done without a lambda. Cf. attachments.
Note: this clrfi is not completely thought out, since for forms such as: (deftype restricted-list (element-type) `(and (satisfies proper-list-p) (satisfies ,(lambda (list)(every (lambda (item) (typep item ',element-type))
list)))))there is no closure (we build a new lambda expression for each use of the type.
If we allowed (satisfies (lambda (...) ...))) we'd have to indicate in what lexical environment the lambda expression would be evaluated (assumedly, the lexical environment of the deftype body). I have not thought about the consequences of that.
-- __Pascal Bourguignon__
<<< text/html; charset=UTF-8; name="clrfi.satisfies-function.html": Unrecognized >>>
<?xml version="1.0" encoding="UTF-8"?> <clp_set name="document-id" value="$Id: //clrfi.alu.org/admin/template/clrfi.clp#11 $" request/> <clp_set name="title" value="SATISFIES PREDICATE BE A FUNCTION SPECIFIED OR A LAMBDA EXPRESSION" request/> <clp_set name="yearnum" value="2005#" request/> <clp_set name="authors" value="Pascal J. Bourguignon" request/> <clp_include_local name="/admin/template/include/header.clp"/> <!-- Visit http://clrfi.alu.org/tools/render-clp.clp to see the page rendered properly. --> <!-- Content starts here. --> <h1>Title</h1> <p><strong>#TITLE#</strong></p> <h2>Author</h2> <p>#IC_REALNAME#</p> <h2>Related CLRFIs, Standards, Dependencies, Conflicts and Replacements</h2> <p> This CLRFI extends the SATISFIES Type Specifier to accept functions (including lambda expressions) in addition to symbols as argument. </p><p> <a href="http://www.lispworks.com/reference/HyperSpec/Body/t_satisf.htm"> HyperSpec SATISFY</a> </p><p> It does not conflict with, relate to or replace any CLRFIs. </p> <h2>Abstract</h2> <p> This CLRFI proposes as an extension to the specification of the Type Specifier SATISFIES, to allow functions and lambda expressions too as predicate. </p> <h2>Rationale</h2> <p></p> <h3>Current Practice</h3> <p> The current practice is to allow only a predicate name, a symbol denoting a function. This complicates the interaction between DEFTYPE and SATISFIES; users need to write: </p><pre> (defpackage "$$RESTRICTED-LIST-PREDICATES$$" (:USE)) (defun find-restricted-list-predicate (element-type) (let* ((name (with-standard-io-syntax (format nil "~S-P" element-type))) (predicate (FIND-SYMBOL name "$$RESTRICTED-LIST-PREDICATES$$"))) (unless predicate (setf predicate (intern name "$$RESTRICTED-LIST-PREDICATES$$")) (eval `(defun ,predicate (list) (every (lambda (item) (typep item ',element-type)) list)))) predicate)) (deftype restricted-list (element-type) `(and (satisfies proper-list-p) (satisfies ,(find-restricted-list-predicate element-type)))) </pre><p> instead of merely: </p><pre> (deftype restricted-list (element-type) `(and (satisfies proper-list-p) (satisfies ,(lambda (list) (every (lambda (item) (typep item ',element-type)) list))))) </pre> <h3>Cost of adoption</h3> <p>The cost would be: <ul> <li> All implementers would have to update their implementations, but the changes are expected to be small. </li><li> This is mostly an upward compatible change: most existing Common Lisp compliant programs would continue to work with no change in semantics. </li><li> Programs of the form: <pre> (handler-case (typep .. '(satisfies (lambda (x) ...))) (error (err) ...)) </pre> or: <pre> (handler-case (typep .. '(satisfies #.(function ...))) (error (err) ...)) </pre> would not work as expected anymore. </ul> </p> <h3>Cost of non-adoption</h3> <p> The interaction between DEFTYPE (which defines actually famillies of types) and SATISFIES is harder for the users. </p> <h2>Specification</h2> <p> <i>Type Specifier</i> <b>SATISFIES</b> </p><p> <<b>Compound Type Specifier Kind:</b> </p><p> Predicating. </p><p> <b>Compound Type Specifier Syntax:</b> </p><p> <b>satisfies</b> <i>predicate</i> </p><p> <b>Compound Type Specifier Arguments:</b> </p><p> <!-- TODO: Add links to CLHS glossary --> <i>predicate</i> --- a function designator, or a lambda expression. </p><p> <b>Compound Type Specifier Description:</b> </p><p> This denotes the set of all objects that satisfy the predicate predicate, which must be either a symbol whose global function definition is a one-argument predicate, a one-argument predicate function, or a one-argument predicate lambda expression. </p><p> For example, the type specifier <code>(and integer (satisfies (lambda (x) (zerop (mod x 3)))))</code> denotes the set of all integers multiple of 3. The form <code>(typep x '(satisfies p)) </code> is equivalent to <code>(if (p x) t nil)</code>. </p><p> The argument is required. The symbol * can be the argument, but it denotes itself (the symbol *), and does not represent an unspecified value. </p> <h2>Reference Implementation</h2> <p> <!-- TODO: *** Let's patch clisp sources... *** --> NONE YET. </p> <h2>Notes</h2> <p> None.</p> <h2>Copyright</h2> <p> Copyright (C) Pascal Bourguignon (2005). All Rights Reserved. </p><p> This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself may not be modified in any way, such as by removing the copyright notice or references to the Common Lisp Request For Improvements process or editors, except as needed for the purpose of developing CLRFIs in which case the procedures for copyrights defined in the CLRFI process must be followed, or as required to translate it into languages other than English. </p><p> The limited permissions granted above are perpetual and will not be revoked by the authors or their successors or assigns. </p><p> This document and the information contained herein is provided on an "AS IS" basis and THE AUTHORS AND THE CLRFI EDITORS DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. </p> <!-- Content ends here. --> <clp_include_local name="/admin/template/include/footer.clp"/> <!-- template.xml == == -->