[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: About the macro expander

From: Pascal J. Bourguignon
Subject: Re: About the macro expander
Date: Sun, 03 Feb 2013 17:13:31 +0100
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/24.2 (gnu/linux)

Xue Fuqiao <address@hidden> writes:

> In the trunk version of (info "(cl) Type Predicates"):
>  -- Macro: cl-deftype name arglist forms...
>      The type specifier `(NAME ARGS...)' is expanded by calling the
>      expander with those arguments; the type symbol `NAME' is expanded
>      by calling the expander with no arguments.  The ARGLIST is
>      processed the same as for `cl-defmacro' except that optional
>      arguments without explicit defaults use `*' instead of `nil' as the
>      "default" default.
> It says "calling the expander with no arguments", but I don't know what
> is the argument of expander (what the argument of expander should be).
> I have searched the Emacs FAQ, Emacs Lisp manual, cl-lib manual and the
> web, but I don't find anything useful.  Can anybody help (is there an
> argument list of the expander)?  Thanks a lot.

Assume we want to define a type for lists of specific length:

    (deftype list-of-length (n) 
       (if (zerop n)
           `(cons t (list-of-length ,(1- n)))))

Now we can specify a type as (list-of-length 3)
and test:  (typep '(1 2 3) '(list-of-length 3))

To test this, the type must be expanded.  So 3 is bound to n, and the
body of the deftype is evaluated, giving: 

  (cons t (list-of-length 2))

Of course, now to check the cdr of (1 2 3), we have to expand
(list-of-length 2), which gives:

  (cons t (cons t (list-of-length 1)))

and again:

  (cons t (cons t (cons t (list-of-length 0))))

and again:

  (cons t (cons t (cons t nil)))

which is the type of a list of length 3.

Now, if we used the type specifier: list-of-length as in:

  (typep '(1 2 3) 'list-of-length)

we would expand (list-of-length) ; <-- no arguments.

Of course, this would give an error, since list-of-length takes one
mandatory parameter (named n).

We could extend the definition of list-of-length saying that if no
argument is given then it reduces to list (ie. lists of any length):

    (deftype list-of-length (&optional (n '*))
       (case n
          ((*)       'list)
          ((0)       'null)
          (otherwise `(cons t (list-of-length ,(1- n))))))

then we can test:

  (typep '(1 2 3) 'list-of-length) --> T

which expands to (list-of-length) therefore n is bound to the default
value *, and the deftype returns the type LIST.  And since (1 2 3) is a
LIST, it's true.

Of course, we can still check:

  (typep '(1 2 3) '(list-of-length 3)) --> T
  (typep '(1 2 3) '(list-of-length 42)) --> NIL

that is, in Common Lisp.  Of course, in emacs lisp it doesn't work,
because it looks like it doesn't expand recursive types.

When trying to understand what (require 'cl) is about, what it aims for,
you can have a look at:
and Practical Common Lisp

__Pascal Bourguignon__           
A bad day in () is better than a good day in {}.

reply via email to

[Prev in Thread] Current Thread [Next in Thread]