From: Paul Rudin
Subject: satisfies type spcifier
Date: 
Message-ID: <m3btf594dq.fsf@shodan.demon.co.uk>
Just as a matter of interest, why does the satisfies type specifier
not allow a lambda expression as its predicate?

TIA.

From: Kent M Pitman
Subject: Re: satisfies type spcifier
Date: 
Message-ID: <sfwogj5z7zg.fsf@world.std.com>
Paul Rudin <·····@shodan.demon.co.uk> writes:

> Just as a matter of interest, why does the satisfies type specifier
> not allow a lambda expression as its predicate?

We were afraid you'd do:

 (defun f (x y)
   (check-type x (satisfies (lambda (y) (<= y x))))
   ...)

which will translate to something like:

 (defun f (x y)
   (unless (typep x '(lambda (y) (<= y x))) ...)
   ...)

which you'll notice uses the lambda expression quoted, and which
means the lexical y is not accessible as a variable to the lambda.
We could have allowed `(satisfies ,#'(lambda ...)) but that would
be problematic to do early checking at compile time.  It would
also cons a lot more.

Basically, by not allowing lambda expressions there, you're not
tricked into doing a host of bad things, which include things that are
both inefficient and semantically confusing.
From: Paul Rudin
Subject: Re: satisfies type spcifier
Date: 
Message-ID: <m3n1yn67ts.fsf@shodan.demon.co.uk>
Kent M Pitman <······@world.std.com> writes:

> Paul Rudin <·····@shodan.demon.co.uk> writes:
> 
> > Just as a matter of interest, why does the satisfies type specifier
> > not allow a lambda expression as its predicate?
> 
> We were afraid you'd do:
> 
>  (defun f (x y)
>    (check-type x (satisfies (lambda (y) (<= y x))))
>    ...)

Although, if I really wanted to, I could do something like:

(defun satisfies-fun (x) (error "I'm waiting for a new definition"))

(defun f (x y)
    (setf (symbol-function 'satisifes-fun) #'(lambda (y) (<= y x)))
    (check-type x (satisfies satisfies-fun))
    ...)

which presumably achieves the same as allowing the lambda directly
in the safisfies specifier?
From: Kent M Pitman
Subject: Re: satisfies type spcifier
Date: 
Message-ID: <sfwr9nz4mxg.fsf@world.std.com>
Paul Rudin <·····@shodan.demon.co.uk> writes:

> Kent M Pitman <······@world.std.com> writes:
> 
> > Paul Rudin <·····@shodan.demon.co.uk> writes:
> > 
> > > Just as a matter of interest, why does the satisfies type specifier
> > > not allow a lambda expression as its predicate?
> > 
> > We were afraid you'd do:
> > 
> >  (defun f (x y)
> >    (check-type x (satisfies (lambda (y) (<= y x))))
> >    ...)
> 
> Although, if I really wanted to, I could do something like:
> 
> (defun satisfies-fun (x) (error "I'm waiting for a new definition"))
> 
> (defun f (x y)
>     (setf (symbol-function 'satisifes-fun) #'(lambda (y) (<= y x)))
>     (check-type x (satisfies satisfies-fun))
>     ...)
> 
> which presumably achieves the same as allowing the lambda directly
> in the safisfies specifier?

No one is trying to stop you from doing the concept, we just wanted
you not to get tricked into using a syntax that would confuse you.
In your example, you end up using #'(lambda ...) which is the right
syntax.  Using '(lambda ...), which you did not do, was what we wanted
to keep you from using it.  So you're saying we did it right.

Incidentally, your example is implemented awfully, maybe just because
it was a quickly written example. But just in case not: This will get
screwed up if in another definition you forget to set the function
definition.  It also doesn't interact well with multi-tasking.  If you
want to stay in the same general space of style, try maybe:

(defvar *my-test* nil)

(defun my-test (x) 
  (funcall (or *my-test* #'(lambda (x) (error "No test active."))) x))

(defun f (x y)
  (let ((*my-test* #'(lambda (y) (<= y x))))
    (check-type x (satisfies my-test))
    ...))

That might work better for you.  Though in the end, it seems just as
useful to do:

(defun f (x y)
  (assert (<= y x) (x y) "Arguments to F must be in ascending order.")
  ...)

Gets at the same idea, without all the baggage of the other approach.

As a rule, I think ASSERT picks up a lot of the cases where a lexical
closure is needed for CHECK-TYPE.  If you think about it, that makes
sense.  A lexical closure is just a function of multiple arguments
which has been curried over some part of its environment in order to
take fewer.  In (check-type x (satisfies something)) the something is 
going to get x as a direct parameter and you're saying you want the
something to get other variables as lexical closure data, but that's really
just the same as taking no arguments and also closing over x.  Further,
since you want an explicit lambda, there's no reason an explicit form 
wouldn't work, as in what assert offers.  And using ASSERT gives symmetry
to the arguments and their relation, instead of forcing the skewed view
that check-type does where one argument is "focused upon" and the others
are not...
From: Paul Rudin
Subject: Re: satisfies type spcifier
Date: 
Message-ID: <m3pv3iwt3l.fsf@shodan.demon.co.uk>
Kent M Pitman <······@world.std.com> writes:

> Paul Rudin <·····@shodan.demon.co.uk> writes:
> 
> > in the safisfies specifier?
> 
> No one is trying to stop you from doing the concept, we just wanted
> you not to get tricked into using a syntax that would confuse you.
> In your example, you end up using #'(lambda ...) which is the right
> syntax.  Using '(lambda ...), which you did not do, was what we wanted
> to keep you from using it.  So you're saying we did it right.

[]

> 
> As a rule, I think ASSERT picks up a lot of the cases where a lexical
> closure is needed for CHECK-TYPE.  If you think about it, that makes
> sense.  A lexical closure is just a function of multiple arguments
> which has been curried over some part of its environment in order to
> take fewer.  In (check-type x (satisfies something)) the something is 
> going to get x as a direct parameter and you're saying you want the
> something to get other variables as lexical closure data, but that's really
> just the same as taking no arguments and also closing over x.  Further,
> since you want an explicit lambda, there's no reason an explicit form 
> wouldn't work, as in what assert offers.  And using ASSERT gives symmetry
> to the arguments and their relation, instead of forcing the skewed view
> that check-type does where one argument is "focused upon" and the others
> are not...



The thing that promted my post was that I noticed that quite often I
was including assertions that checked the types of all the elements of
a list. (This isn't something that end up in code that goes to
customers, so I'm not really concerned about effeciency here.)

So maybe I'd have 

(assert (every #'(lambda (x) (check-type x some-type)) lyst))

or some such. So I thought: OK I'll write a deftype so that I can
write:

(check-type lyst (list-of some-type))

instead.

I haven't really used deftype much so far, so I wrote something like:

(deftype list-of (x) 
  `(satisfies ,#'(lambda (y) 
                   (and (listp y)
                        (every #'(lambda (z) (typep z x))
                               y)))))

when I couldn't get this to work I checked and discovered that
satisfies requires a function name which, in this case, seems
superflous.






 
From: Kent M Pitman
Subject: Re: satisfies type spcifier
Date: 
Message-ID: <sfwaeum4cpe.fsf@world.std.com>
Paul Rudin <·····@shodan.demon.co.uk> writes:

> I haven't really used deftype much so far, so I wrote something like:
> 
> (deftype list-of (x) 
>   `(satisfies ,#'(lambda (y) 
>                    (and (listp y)
>                         (every #'(lambda (z) (typep z x))
>                                y)))))
> 
> when I couldn't get this to work I checked and discovered that
> satisfies requires a function name which, in this case, seems
> superflous.

It doesn't seem superfluous to me.

Are you saying you'd like it to also be able to be a function object?
A function object is not a lambda expression, which is what you'd
said before.  A lambda expression is a list whose care is lambda.
A function object which results from a (FUNCTION ...) expression or
the evaluation of a lambda expression, is not what you asked about.

Note that I'm still a little nervous about that because it suggests that
 (typep x '(satisfies #.#'...))
would become a valid expression, and this might be problematic to
externalize to a file.  But certainly this is a more modest request
than what you originally (perhaps indadvertently) asked for.
From: ·······@my-deja.com
Subject: Re: satisfies type spcifier
Date: 
Message-ID: <7j05qj$rh$1@nnrp1.deja.com>
In article <···············@world.std.com>,
  Kent M Pitman <······@world.std.com> wrote:

> (defvar *my-test* nil)
>
> (defun my-test (x)
>   (funcall (or *my-test* #'(lambda (x) (error "No test active."))) x))
>
> (defun f (x y)
>   (let ((*my-test* #'(lambda (y) (<= y x))))
>     (check-type x (satisfies my-test))
>     ...))
>
> That might work better for you.  Though in the end, it seems just as
> useful to do:

This is better here, but in the context of a deftype I don't think it
helps, because you can't use (let ((*my-test*... in the exapansion of
the deftype because the predicate isn't called till after the dynamic
scope of the let has expired


>
> (defun f (x y)
>   (assert (<= y x) (x y) "Arguments to F must be in ascending order.")
>   ...)
>
> Gets at the same idea, without all the baggage of the other approach.
>
> As a rule, I think ASSERT picks up a lot of the cases where a lexical
> closure is needed for CHECK-TYPE.  If you think about it, that makes
> sense.  A lexical closure is just a function of multiple arguments
> which has been curried over some part of its environment in order to
> take fewer.  In (check-type x (satisfies something)) the something is
> going to get x as a direct parameter and you're saying you want the
> something to get other variables as lexical closure data, but that's
really
> just the same as taking no arguments and also closing over x.
> Further,
> since you want an explicit lambda, there's no reason an explicit form
> wouldn't work, as in what assert offers.  And using ASSERT gives
symmetry
> to the arguments and their relation, instead of forcing the skewed
view
> that check-type does where one argument is "focused upon" and the
others
> are not...

I'd prefer to be able to use `deftype' `check-type' and `the' for type
checking, which doesn't seem unreasonable. Otherwise I soon end up in
the situation where I have a separate, parallel type checking system to
the one in the language spec.

I'd also like to use `the' with types I've declared. (Especially since
our compiler also does a type check with appropriate safety settings in
this situation.)

Incidentally, I mentioned this to someone else, and their response was
something along the lines of "Oh yes, you need my compiler patch that
enables that...", which is also OK; but in a perfect world I'd prefer
code that'll work with any ANSI compliant compiler.


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.