From: Slobodan Blazeski
Subject: Few questions about  deftype, subtype and initialization
Date: 
Message-ID: <93c0a6d9-6f2c-494b-9624-734e24025c94@e4g2000hsg.googlegroups.com>
I want to make a new type named email that is subtype  of type string
and validated through email-p function:
(defun email-p (email)
  (let ((scanner (create-scanner *jeffrey-friedl*)))
    (scan scanner email)))

(deftype email () '(and string (satisfies email-p)))


1st   Is above definition correct ?
2nd How to create something of specific type in the REPL? Something
like make-array or make-string for the  squences or like int x = 0 in
c/c++.  Is it possible to do that for types  like integer and my own
defined type like above email.
3rd In the hyperspec example for deftype

 (defun equidimensional (a)
   (or (< (array-rank a) 2)
       (apply #'= (array-dimensions a)))) =>  EQUIDIMENSIONAL
 (deftype square-matrix (&optional type size)
   `(and (array ,type (,size ,size))
         (satisfies equidimensional))) =>  SQUARE-MATRIX

What does  array in (array ,type (,size ,size)) represent ? The first
place in the list is function, macro or special operator but array is
a system class. What it's doing over there?  I'm completely confused.

thanks
Slobodan

From: Vassil Nikolov
Subject: Re: Few questions about  deftype, subtype and initialization
Date: 
Message-ID: <snwk5mp4583.fsf@luna.vassil.nikolov.names>
Slobodan Blazeski <·················@gmail.com> writes:

> I want to make a new type named email that is subtype  of type string
> and validated through email-p function:
> (defun email-p (email)
>   (let ((scanner (create-scanner *jeffrey-friedl*)))
>     (scan scanner email)))
>
> (deftype email () '(and string (satisfies email-p)))
>
>
> 1st   Is above definition correct ?

  Yes, but note that what it directly does is to define a new type
  specifier, EMAIL.  It specifies the type that is comprised of all
  (infinitely many) Common Lisp objects that are (a) strings (i.e. of
  type STRING) and (b) such that EMAIL-P returns true when applied to
  any of them.

  To create a value of that type, you would create a string (with any
  of a number of functions) while ensuring that the string so created
  satisfies EMAIL-P.  For example,

    (defun make-email (s)
      (let ((v (coerce s 'string)))
        (check-type v (satisfies email-p))
        v))

  is a trivial constructor (perhaps not very useful except to
  illustrate the point).

  Note that STRING is a built-in class, which means that subclassing
  it is restricted.

> ...
> What does array in (array ,type (,size ,size)) represent ?

  In this case, one of the words in Common Lisp's language of type
  specifiers.  In that language, (ARRAY type (m n)) is an expression
  that denotes the type of an object which is a two-dimensional m x n
  array whose elements are of the given type.

  ---Vassil.


-- 
Bound variables, free programmers.
From: Kent M Pitman
Subject: Re: Few questions about  deftype, subtype and initialization
Date: 
Message-ID: <uprwhuml7.fsf@nhplace.com>
Slobodan Blazeski <·················@gmail.com> writes:

> I want to make a new type named email that is subtype  of type string
> and validated through email-p function:
> (defun email-p (email)
>   (let ((scanner (create-scanner *jeffrey-friedl*)))
>     (scan scanner email)))
> 
> (deftype email () '(and string (satisfies email-p)))
> 
> 
> 1st   Is above definition correct ?

Assuming that email-p takes a string, it looks right.  I didn't try it.

> 2nd How to create something of specific type in the REPL? Something
> like make-array or make-string for the  squences or like int x = 0 in
> c/c++.  Is it possible to do that for types  like integer and my own
> defined type like above email.

First, sequence is an abstract type; that is, there are no direct 
instances of sequence, so making it doesn't make any sense to do other
than make specific types. You can make the specific types of arrays or
strings by using appropriate calls to MAKE-ARRAY with given element types.

But... You have to make something of the concrete class that is somehow
arranged to do the right thing.  More things can be type specifiers than
can be created; some types exist for declaration only and cannot even be
tested for.  Some exist for declaration and discrimination (that is, a test
exists to see if the thing is of that type).  And some exist for declaration, 
discrimination, and creation (that is, a thing of that type can actually be
created).  For example, you certainly cannot do
 (make-email)
nor
 (make-instance 'email)
since there would be no way to work backward from a type like 
 (and string (satisfies email-p))
to something that could construct one. 

Things defined with defstruct can be created with the constructor for the
type.  Things defined with defclass can be created with MAKE-INSTANCE.

> 3rd In the hyperspec example for deftype
> 
>  (defun equidimensional (a)
>    (or (< (array-rank a) 2)
>        (apply #'= (array-dimensions a)))) =>  EQUIDIMENSIONAL
>  (deftype square-matrix (&optional type size)
>    `(and (array ,type (,size ,size))
>          (satisfies equidimensional))) =>  SQUARE-MATRIX
> 
> What does  array in (array ,type (,size ,size)) represent ?

DEFTYPE expands a typespec into another type spec.  That is not a macro
and its output is not evaluable.  SQUARE-MATRIX _is_ a type that you
can use for TYPEP, and it expands into a typespec you can use for TYPEP, too.

> The first place in the list is function, macro or special operator 

Only in an evaluable form, not in a type specifier.

  type specifier n. an expression that denotes a type.
   ``The symbol random-state, the list (integer 3 5),
     the list (and list (not null)), and the class named
     standard-class are type specifiers.'' 

  Source: http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_t.htm#type_specifier

Type specifiers are either:

  atomic type specifier n. a type specifier that is atomic. 
    For every atomic type specifier, x, there is an equivalent compound
    type specifier with no arguments supplied, (x). 

  Source: http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_a.htm#atomic_type_specifier

or
  compound type specifier n. a type specifier that is a cons;
    i.e., a type specifier that is not an atomic type specifier.
    ``(vector single-float) is a compound type specifier.'' 

  Source: http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_c.htm#compound_type_specifier

For compound type specifiers, they are a list of a type name and arguments 
to the type.

You probably want to read
  4.2.3 Type Specifiers
  http://www.lispworks.com/documentation/HyperSpec/Body/04_bc.htm
and then some things like:
  http://www.lispworks.com/documentation/HyperSpec/Body/t_array.htm#array

> but array is a system class. 

Yes, it is.  Classes are types.  Class names are type names, and so are type
specifiers.  Lists starting with type specifiers are compound type specifiers
for that type.  Some compound type specifiers take arguments, which is why
deftype takes arguments.

> What it's doing over there?

Being a type specifier, naming a class (and, by implication, a type).

> I'm completely confused.

Wrong.  You are only partly confused.  You had some of the above right. :)
From: Vassil Nikolov
Subject: Re: Few questions about  deftype, subtype and initialization
Date: 
Message-ID: <snw7iip3uuu.fsf@luna.vassil.nikolov.names>
Kent M Pitman <······@nhplace.com> writes:
> ...
>  (make-email)

  There is a way to twist this so that the above would work, e.g.

    (defun make-email (&key (localpart (username)) (domain (hostname)))
      (format nil ···@~A" localpart domain))

  in a sort of a divide-and-conquer way, again, at least for
  illustrative purposes.  One can then think of constructors for the
  local part and the domain part.  (The two hypothetical functions
  used above would be implementation-dependent, e.g. using
  (SB-UNIX:UID-USERNAME (SB-POSIX:GETEUID)) and
  (SB-UNIX:UNIX-GETHOSTNAME) in SBCL.)

  Of course, whether or not that is the way to go for library-grade
  code depends on the purpose (is this for a facility to collect/list
  addresses, or to handle them in a MUA, or in an MTA?).  Such
  considerations would determine whether or not it is overkill to seek
  a structured representation of e-mail addresses (akin to pathnames),
  rather than plain "emailstrings".  Etc.

  ---Vassil.


-- 
Bound variables, free programmers.
From: Kent M Pitman
Subject: Re: Few questions about  deftype, subtype and initialization
Date: 
Message-ID: <uve686eak.fsf@nhplace.com>
Vassil Nikolov <···············@pobox.com> writes:

> Kent M Pitman <······@nhplace.com> writes:
> > ...
> >  (make-email)
> 
>   There is a way to twist this so that the above would work, e.g.
> 
>     (defun make-email (&key (localpart (username)) (domain (hostname)))

Sure.  I didn't mean to say you can't make such a function.  What I tried
to say was that Lisp cannot infer one for you, in the way it mostly can
if you define your type with defstruct or defclass.  [Of course, even with
defclass, it's a philosophical question whether it can really infer a
constructor or whether if you need to write a make-instance method, or
whatever, that's perhaps proof that Lisp can't infer the right constructor
without a hint.]

>   Of course, whether or not that is the way to go for library-grade
>   code depends on the purpose (is this for a facility to collect/list
>   addresses, or to handle them in a MUA, or in an MTA?).  Such
>   considerations would determine whether or not it is overkill to seek
>   a structured representation of e-mail addresses (akin to pathnames),
>   rather than plain "emailstrings".  Etc.

I absolutely think you can make such a constructor, and wasn't trying to
address the issue of robustness.  I was speaking narrowly to automatic 
effects--to the "where is the constructor?" question--and trying to say
"you have to write it", not "you can't write it".  (Of course, I might have
been misunderstanding whether this was the question.)
From: Vassil Nikolov
Subject: Re: Few questions about  deftype, subtype and initialization
Date: 
Message-ID: <snwve683gd5.fsf@luna.vassil.nikolov.names>
Kent M Pitman <······@nhplace.com> writes:

> Vassil Nikolov <···············@pobox.com> writes:
>
>> Kent M Pitman <······@nhplace.com> writes:
>> > ...
>> >  (make-email)
>> 
>>   There is a way to twist this so that the above would work, e.g.
>> 
>>     (defun make-email (&key (localpart (username)) (domain (hostname)))
>
> Sure.  I didn't mean to say you can't make such a function.  What I tried
> to say was that Lisp cannot infer one for you, in the way it mostly can
> if you define your type with defstruct or defclass.  [Of course, even with
> defclass, it's a philosophical question whether it can really infer a
> constructor or whether if you need to write a make-instance method, or
> whatever, that's perhaps proof that Lisp can't infer the right constructor
> without a hint.]

  It may well have been I who misunderstood the question.  It is an
  interesting question in any case (I'm sure it is, even if I am still
  misunderstanding it).

  By the way, I think that using (AND STRING (SATISFIES EMAIL-P)) is
  an (implicit) attempt to simulate the hypothetical and non-standard

    (defclass email (string) ...)  ;[*]

  which wouldn't automatically yield a no-argument constructor, since
  there is none for STRING (thought there might have been one, much
  like LIST can be called with no arguments).

  [*] for what it's worth, one can't say ``class Email extends String''
      in Java, either

  On the other hand, one might opt for composition, rather than
  inheritance, along the lines of

    (defconstant =null-email= ·······@localhost")

    (defclass email ()
      ((address :accessor email-address
                :initarg :address
                :initform =null-email=)))

    (defmethod print-object ((x email) s)
      (print-unreadable-object (x s :type t)
        (prin1 (email-address x) s)))

    (make-instance 'email)  ;no arguments?
    => #<email ·······@localhost">

  and I think this is where the philosophical question kicks in.
  (I "cheated" by supplying a default value from within, didn't I?)

  The validation part is missing from the above, but it can be added
  without undue pain:

    (defmethod shared-initialize :after ((x email) slot-names &rest initargs)
      (declare (ignore slot-names initargs))
      (check-type (email-address x) (and string (satisfies email-p))))

  ---Vassil.


-- 
Bound variables, free programmers.
From: Vassil Nikolov
Subject: "minimal" constructor calls (Ex: Few questions about  deftype, subtype and initialization)
Date: 
Message-ID: <snwk5mo2v5s.fsf_-_@luna.vassil.nikolov.names>
This matter about no-argument constructors led to me to come up with
the following list, for standard Common Lisp facilities (it would
probably be interesting, but rather time-consuming, to survey various
libraries as well).  I hope it gives some additional perspective; I
also hope that the informal meaning of "null", "quasi-null", and
"minimum" can be derived from the context.  Some of the entries may be
debatable; I certainly don't claim that this is a definitive
treatment.


"Minimal" constructor calls:
(the simplest calls returning an object of a given type)


1. "Null" construction (no arguments at all).

condition                (MAKE-CONDITION 'FOO)
hash table               (MAKE-HASH-TABLE)
list                     (LIST)
pathname                 (MAKE-PATHNAME)
random state             (MAKE-RANDOM-STATE)
readtable                (COPY-READTABLE)
user-defined class       (MAKE-INSTANCE 'FOO)
user-defined structure   (MAKE-FOO)
vector                   (VECTOR)


2. "Quasi-null" construction ("minimum" value(s) of argument(s)).

array                    (MAKE-ARRAY NIL)
character                (CODE-CHAR 0)
complex                  (COMPLEX 0.0 0.0)
cons                     (CONS NIL NIL)
function                 (LAMBDA ())
package                  (MAKE-PACKAGE "")
stream                   (OPEN "")  ;implementation-dependent
string                   (MAKE-STRING 0)
symbol                   (MAKE-SYMBOL "")


3. Other.

ratio                    (/ 1 2)


Note: these entries illustrate what is allowed, not necessarily what
makes good sense (that depends on context, after all).  In any case,
it should be possible to use the values produced by the above forms in
test suites.

---Vassil.


-- 
Bound variables, free programmers.
From: Robert Uhl
Subject: Re: Few questions about  deftype, subtype and initialization
Date: 
Message-ID: <m3k5morrm4.fsf@latakia.dyndns.org>
Kent M Pitman <······@nhplace.com> writes:

>  For example, you certainly cannot do
>  (make-email)
> nor
>  (make-instance 'email)
> since there would be no way to work backward from a type like 
>  (and string (satisfies email-p))
> to something that could construct one. 

Well, strictly speaking the implementation could infer from the type
that it needs to be a string, then it could brute-force start with "",
then on to "a", "b" ... "aa", "ab" and so forth until finding a string
which satisfies EMAIL-P.  Performance of this hypothetical
INFERRED-MAKE-EMAIL would not perhaps be what one might wish it to be,
though.

-- 
Robert Uhl <http://public.xdi.org/=ruhl>
When Moses came down off the mountain, it was with raw ASCII text chiseled into
stone; not DHTML, JavaScript, Unicode and animated GIFs.               --Tanuki
From: Kent M Pitman
Subject: Re: Few questions about  deftype, subtype and initialization
Date: 
Message-ID: <uy7b3lxk9.fsf@nhplace.com>
Robert Uhl <·········@NOSPAMgmail.com> writes:

> Kent M Pitman <······@nhplace.com> writes:
> 
> >  For example, you certainly cannot do
> >  (make-email)
> > nor
> >  (make-instance 'email)
> > since there would be no way to work backward from a type like 
> >  (and string (satisfies email-p))
> > to something that could construct one. 
> 
> Well, strictly speaking the implementation could infer from the type
> that it needs to be a string, then it could brute-force start with "",
> then on to "a", "b" ... "aa", "ab" and so forth until finding a string
> which satisfies EMAIL-P.  Performance of this hypothetical
> INFERRED-MAKE-EMAIL would not perhaps be what one might wish it to be,
> though.

I'm sure you meant to be humorous, but...  No, it can't even do that.

The point is that to make a constructor, the first thing you have to do
is allow dataflow into it.  I guess I misstated things above in a way that
was misleading when I didn't write (make-email ...) or 
(make-instance 'email ...) but clearly the ability to make _some_ kind of
instance of the thing is not the same as having a constructor of the instance.
For example, you'd likely want a constructor that took a name and host part, 
and yet even the difficulty of knowing that
 (make-email "abc" "def")
and knowing that the first part is the name and the second the host is
beyond the scope of what you can reliably do by trial and error, since nothing
syntactically prevents the reverse interpretation of the args.

Nor even if you knew the order of the args could you infer that just because
there was a constructor, there was a valid value you could pass to the 
instructor.  For example, a inferring a constructor for the type NIL would 
be tough.  But also, consider the type

 (defun fermat-counter-example-p (candidate) ;untested
   (and (listp candidate)
        (= (length candidate) 4)
        (every #'integerp candidate)
        (destructuring-bind (n a b c) candidate
          (and (> n 2)
               (= (expt a n) (+ (expt b n) (expt c n)))))))

 (deftype fermat-counter-example () ;untested
   `(satisfies fermat-counter-example-p))

Enumerating ideas is not going to find you fame and fortune.  So if by
"performance" you mean to include "provably never going to yield a result",
then yes, there is a performance bottleneck.  But really, the inability to
do something is qualitatively different than just taking a long time.
From: Robert Uhl
Subject: Re: Few questions about  deftype, subtype and initialization
Date: 
Message-ID: <m3wsqmqnzr.fsf@latakia.dyndns.org>
Kent M Pitman <······@nhplace.com> writes:

> Robert Uhl <·········@NOSPAMgmail.com> writes:
>
>> Kent M Pitman <······@nhplace.com> writes:
>> 
>> >  For example, you certainly cannot do
>> >  (make-email)
>> > nor
>> >  (make-instance 'email)
>> > since there would be no way to work backward from a type like 
>> >  (and string (satisfies email-p))
>> > to something that could construct one. 
>> 
>> Well, strictly speaking the implementation could infer from the type
>> that it needs to be a string, then it could brute-force start with "",
>> then on to "a", "b" ... "aa", "ab" and so forth until finding a string
>> which satisfies EMAIL-P.  Performance of this hypothetical
>> INFERRED-MAKE-EMAIL would not perhaps be what one might wish it to be,
>> though.
>
> I'm sure you meant to be humorous, but...  No, it can't even do that.

I beg to differ--any CL implementation faced with (and string (satisfies
email-p)) _could_ define a pessimal (make-email) which might not ever
return: it'd try string after string after string until one met EMAIL-P.

But yes, I was going for the joke.

> The point is that to make a constructor, the first thing you have to
> do is allow dataflow into it.  I guess I misstated things above in a
> way that was misleading when I didn't write (make-email ...) or
> (make-instance 'email ...) but clearly the ability to make _some_ kind
> of instance of the thing is not the same as having a constructor of
> the instance.

Well, gosh, if you want _arguments_ to MAKE-EMAIL, then the whole
thing's off *grin*

You're quite right that being able to construct some random instance is
not the same thing as properly constructing an instance from given data,
and that (as currently defined) Common Lisp is unable to automatically
meet that challenge.

Not that I hold that against the language--I think in the general case
it may very well be undecidable; in particular cases a wrapper for
deftpye could no doubt do the trick.

-- 
Robert Uhl <http://public.xdi.org/=ruhl>
The Lord of the Rings is an historical novel, and the trivial fact that
its history is a fictional one is really beside the point.
                              --The Encyclopaedia of Arda
From: Rainer Joswig
Subject: Re: Few questions about  deftype, subtype and initialization
Date: 
Message-ID: <joswig-A22293.23104304012008@news-europe.giganews.com>
In article 
<····································@e4g2000hsg.googlegroups.com>,
 Slobodan Blazeski <·················@gmail.com> wrote:

> I want to make a new type named email that is subtype  of type string
> and validated through email-p function:
> (defun email-p (email)
>   (let ((scanner (create-scanner *jeffrey-friedl*)))
>     (scan scanner email)))
> 
> (deftype email () '(and string (satisfies email-p)))
> 
> 
> 1st   Is above definition correct ?
> 2nd How to create something of specific type in the REPL? Something
> like make-array or make-string for the  squences or like int x = 0 in
> c/c++.  Is it possible to do that for types  like integer and my own
> defined type like above email.
> 3rd In the hyperspec example for deftype
> 
>  (defun equidimensional (a)
>    (or (< (array-rank a) 2)
>        (apply #'= (array-dimensions a)))) =>  EQUIDIMENSIONAL
>  (deftype square-matrix (&optional type size)
>    `(and (array ,type (,size ,size))
>          (satisfies equidimensional))) =>  SQUARE-MATRIX
> 
> What does  array in (array ,type (,size ,size)) represent ? The first
> place in the list is function, macro or special operator but array is
> a system class. What it's doing over there?  I'm completely confused.

You should look at the definition for the types of types. ;-)

http://www.lispworks.com/documentation/HyperSpec/Body/04_bc.htm

ARRAY is an 'atomic type specifier'.

AND and SATISFIES are 'compound type specifier names'.

So, in (array ,type (,size ,size)) ARRAY is an atomic type specifier.

If you say as a type  (square-matrix number 3) then this will be expanded
into the type  (and (array number (3 3)) (satisfies equidimensional))  .

AND combines two types.
http://www.lispworks.com/documentation/HyperSpec/Body/t_and.htm






> 
> thanks
> Slobodan

-- 
http://lispm.dyndns.org/