Le 21/02/2024 à 22:10, Marco Antoniotti a écrit :
Hi

I 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                     ==                     ==          -->

Reply via email to