Hi Pascal

this works in LW

CL-USER 21 >
*(deftype msb (&optional (bits 8))               `(satisfies ,(curry1
'msb-test bits)))*
*MSB*

CL-USER 22 > *(typep 42 '(msb 6))* ; Less than or equal to 6, fail.
*NIL*

CL-USER 23 > *(typep 42 '(msb 7)) *; Greater than or equal to 7, succeed.

*T*

The function *CURRY1* just curries one argument and *MSB-TEST* does the
check, taking two arguments, the second being the object to *typep*
(details irrelevant; trust me: it works).

I know: done too much Haskell recently.

MA

On Wed, Feb 21, 2024 at 11:45 PM Pascal Bourguignon <p...@informatimago.com>
wrote:

> 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__
>

Reply via email to