[Ecls-list] (function * t) type specifier is no longer accepted

Stas Boukarev stassats at gmail.com
Tue Dec 18 12:58:55 UTC 2012


Juan Jose Garcia-Ripoll <juanjose.garciaripoll at googlemail.com> writes:

> On Fri, Jun 1, 2012 at 12:20 PM, Stas Boukarev <stassats at gmail.com> wrote:
>
>> As per CLHS,
>> http://www.lispworks.com/documentation/lw50/CLHS/Body/04_bc.htm
>> "*" means unspecified part of the type specifier.
>>
>> (declaim (ftype (function * integer) f))
>>
>> (defun f (a)
>>  (1+ a))
>>
>> and then (compile-file "file.lisp")
>>
>> ;;; LAMBDA: Illegal lambda list *.
>
>
> Actually, the behavior you expect is undefined. While * is used to design
> parts of the type that are general, not specified, the situations in which
> * is used are very precisely marked by the Standard. Note for instance the
> difference between the grammar for the ARRAY type
>
> http://www.lispworks.com/documentation/lw50/CLHS/Body/t_array.htm#array
>
> and that of the FUNCTION type
>
> http://www.lispworks.com/documentation/lw50/CLHS/Body/t_fn.htm
>
> Only the former allows *
>
> One could allow ECL to "support" * by ignoring all function declarations
> where it appears. I presume this would help with certain libraries that use
> these nonstandard types.
Let's revisit this.

I'm not convinced that it is illegal.
http://www.lispworks.com/documentation/lw50/CLHS/Body/04_bc.htm
says
"If a type specifier is a list, the car of the list is a symbol, and the
rest of the list is subsidiary type information."
(function ..) fits that.
Now it states "Except as explicitly stated otherwise, the subsidiary
items can be unspecified."
Ok, we check
http://www.lispworks.com/documentation/lw50/CLHS/Body/t_fn.htm
nowhere does it state that it's not allowed.

Back to 4.2.3
"If a list has one or more unspecified items at the end, those items can
be dropped. If dropping all occurrences of * results in a singleton
list, then the parentheses can be dropped as well (the list can be
replaced by the symbol in its car). For example, (vector double-float *)
can be abbreviated to (vector double-float), and (vector * *) can be
abbreviated to (vector) and then to vector." 

So, just FUNCTION is allowed, but according to the above, it's the same
as (function * *).

It is indeed true that for other compound type specifiers * is
explicitly mentioned as allowed.

But what about cases when it's not allowed?
There's a table of
"compound type specifier names but that cannot be used as atomic type
specifiers."
and     mod  satisfies  
eql     not  values     
member  or

======

and
http://www.lispworks.com/documentation/lw50/CLHS/Body/t_and.htm
* is not permitted as an argument.

eql
http://www.lispworks.com/documentation/lw50/CLHS/Body/t_eql.htm
The object can be *, but if so it denotes itself (the symbol *) and does
not represent an unspecified value.

member
http://www.lispworks.com/documentation/lw50/CLHS/Body/t_member.htm
* can be among the objects, but if so it denotes itself (the symbol *)
and does not represent an unspecified value.

not
http://www.lispworks.com/documentation/lw50/CLHS/Body/t_not.htm
The argument is required, and cannot be *.

or
http://www.lispworks.com/documentation/lw50/CLHS/Body/t_or.htm
* is not permitted as an argument.

http://www.lispworks.com/documentation/lw50/CLHS/Body/t_satisf.htm
The symbol * can be the argument, but it denotes itself (the symbol *),
and does not represent an unspecified value. 

values
http://www.lispworks.com/documentation/lw50/CLHS/Body/t_values.htm
he symbol * may not be among the value-types.

======

So, all of them very explicitly forbid *. FUNCTION just happens to be
the only of compound type-specifiers which can be used as just
"function" and which doesn't mention *. Now why the type-specifiers above
forbid */have a different meaning? Because it doesn't make sense for it
to appear there. What would (not *) mean? Nonsense. But does it make
sense for FUNCTION to have *? Of course, it would just mean that such a
part can be anything, and indeed just "FUNCTION" working fine is an
evidence of this. Is it useful? It is, (function * fixnum) denotes that
it accepts whatever but returns a fixnum.
Now somebody might say "But you can use (function (&rest t) fixnum)
instead, which cannot be said for (vector *), because it has a different
meaning from (vector t)." That's true, but (cons *) is equivalent to
(cons t), and yet it's explicitly allowed:
http://www.lispworks.com/documentation/lw50/CLHS/Body/t_cons.htm

And let's look at the other parts of the standard. It has a lot of
instances where things are not explicitly mentioned, but are implied
from other parts, for example:

http://www.lispworks.com/documentation/lw50/CLHS/Body/19_bc.htm
"Except as explicitly specified otherwise, for functions that manipulate
or inquire about files in the file system, the pathname argument to such
a function is merged with *default-pathname-defaults* before accessing
the file system (as if by merge-pathnames)."

and http://www.lispworks.com/documentation/lw50/CLHS/Body/f_dir.htm
doesn't mention anywhere that it merges the pathname, and yet nobody
disputes that it should.

And it even has the same wording "Except as explicitly stated
otherwise".

I have no doubt that (function * t) is a valid and useful
type-specifier, and all other implementations accept it.

-- 
With best regards, Stas.




More information about the ecl-devel mailing list