Predicates

Nyquist / XLISP 2.0 - Contents | Tutorials | Examples | Reference

# Predicates and Comparison

Lisp has extensive support for run-time tests.

Generalized Lisp Functions - slower than the build-ins, but no errors

1. Built-in XLISP Functions
2. Generalized Comparison - one or more arguments

- equalp - compares expressions with 'equality' functions.

3. Symbol Predicates - one argument

- variablep - is this a symbol with a variable value bound to it?
- functionp - is this a function or a symbol with a function value bound to it?
- specialp - is this a special form or a symbol with a special form bound to it?
- macrop - is this a Lisp macro or a symbol with a Lisp macro bound to it?

4. Function Predicates - one argument

- subrp - is this a build-in function?
- fsubrp - is this a build-in special form?
- closurep - is this a user-defined function?

5. Character Predicates - one argument

- POSIX Character Classes

Back to top

## Built-in XLISP Functions

1. Boolean Predicates - one argument [all types]

- not - does this expression evaluate to false?

2. Generalized Comparison - two arguments [all types]

- eq - are the expressions identical?
- eql - are the expressions identical or equal numbers?
- equal - do the printed expressions look the same?

3. Type Predicates - one argument [all types]

- atom - is this an atom?
- symbolp - is this a symbol?

- Symbol Predicates - one argument [error if not a symbol]

- boundp - has the symbol a variable value?
- fboundp - has the symbol a function value?

- numberp - is this a number?

- Number Predicates - one argument [error if not a number]

- plusp - is the number positive?
- minusp - is the number negative?
- zerop - is the number equal to zero?
- integerp - is the number an integer?

- Integer Predicates - one argument [error if not an integer]

- evenp - is the integer even?
- oddp - is the integer odd?

- floatp - is the number a floating-point number?

- Numerical Comparison - one or more arguments [error if not numbers only]

- < - true if all numbers are monotonically increasing
- <= - true if all numbers are monotonically nondecreasing
- = - true if all all numbers are the same value
- /= - true if no two numbers have the same value
- >= - true if all numbers are monotonically nonincreasing
- > - true if all numbers are monotonically decreasing

- null - is this an empty list?
- consp - is it a non-empty list?
- listp - is this a list?

- List Predicates - one argument [error if not a list]

- endp - is this the end of a list?

- stringp - is this a string?

- String Comparison - one or more arguments [error if not strings only]

- Case Sensitive

- string< - test for less than in ASCII ordering
- string<= - test for less than or equal to in ASCII ordering
- string= - test for equal to in ASCII ordering
- string/= - test for not equal to in ASCII ordering
- string>= - test for greater than or equal to in ASCII ordering
- string> - test for greater than in ASCII ordering

- Case Insensitive

- string-lessp - is this less than in ASCII ordering ?
- string-not-greaterp - is this not greater than in ASCII ordering ?
- string-equal - is this equal in ASCII ordering ?
- string-not-equal - is this not equal in ASCII ordering ?
- string-not-lessp - is this not less than in ASCII ordering ?
- string-greaterp - is this greater than in ASCII ordering ?

- See also Unicode examples.

- characterp - is this a character?

- Character Predicates - one argument [error if not a character]

- upper-case-p - is this an upper case character?
- lower-case-p - is this a lower case character?
- both-case-p - is this an alphabetic [either case] character?
- digit-char-p - is this a digit character?
- alphanumericp - is this an alphabetic or a digit character?
- See also POSIX Character Classes.

- Character Comparison - one or more arguments [error if not characters only]

- Case Sensitive

- char< - test for less than in ASCII ordering
- char<= - test for less than or equal to in ASCII ordering
- char= - test for equal to in ASCII ordering
- char/= - test for not equal to in ASCII ordering
- char>= - test for greater than or equal to in ASCII ordering
- char> - test for greater than in ASCII ordering

- Case Insensitive

- char-lessp - is this less than in ASCII ordering?
- char-not-greaterp - is this not greater than in ASCII ordering ?
- char-equal - is this equal in ASCII ordering?
- char-not-equal - is this not equal in ASCII ordering?
- char-not-lessp - is this not less than in ASCII ordering ?
- char-greaterp - is this greater than in ASCII ordering?

- See also Unicode examples.

- arrayp - is this an array?
- streamp - is this a stream?
- objectp - is this an object?
- filep - is this a file?
- soundp - is this a sound?

Back to top

## equalp

Two expressions are 'equalp':

- If two numbers are = numerical equal.

- If two characters are char-equal.

- If two strings are string-equal.

- If the two cars in conses are 'equalp' and the two cdrs in conses are 'equalp'.

- If two arrays have the same number of elements and dimensions, and the corresponding elements in all dimensions are 'equalp'.

    (defun equalp (expr-1 expr-2)
      (or (equal expr-1 expr-2)
          (and (numberp expr-1) (numberp expr-2) (= expr-1 expr-2))
          (let ((type (type-of expr-1)))
            (when (eq type (type-of expr-2))
              (case type
                (character (char-equal expr-1 expr-2))
                (string    (string-equal expr-1 expr-2))
                (cons      (do ((x (first expr-1)
                                   (if (consp expr-1) (first expr-1) expr-1))
                                (y (first expr-2)
                                   (if (consp expr-2) (first expr-2) expr-2)))
                               ((or (null expr-1)
                                    (null expr-2)
                                    (not (equalp x y)))
                                (and (null expr-1)
                                     (null expr-2)))
                             (setq expr-1 (and (consp expr-1) (rest expr-1))
                                   expr-2 (and (consp expr-2) (rest expr-2)))))
                (array     (let ((end (length expr-1)))
                             (when (eql end (length expr-2))
                               (dotimes (index end t)
                                 (and (not (equalp (aref expr-1 index)
                                                   (aref expr-2 index)))
                                      (return nil)))))))))))

cons: I used do instead of recursion because XLISP has only two kilobytes stack size. The (consp expr) tests are necessary because in a dotted list the last rest element is not a cons.

Examples:

    (equalp 1 1.0)                            => T
    (equalp #\a #\A)                          => T
    (equalp "Abc" "aBc")                      => T
    (equalp '(1 #\a "Abc") '(1.0 #\A "aBc"))  => T
    (equalp #(1 #\a "Abc") #(1.0 #\A "aBc"))  => T

Nested expressions only match if the nesting matches:

    (equalp '(1 (2 3)) '(1.0 (2.0 3.0))  => T
    (equalp '(1 (2 3)) '((1.0 2.0) 3.0)  => NIL
    (equalp '((1 2) 3) '((1.0 2.0) 3.0)  => T
    (equalp '((1 2) 3) '(1.0 (2.0 3.0))  => NIL

A character does not match a string with the same character:

    (equalp #\a "a")  => NIL

Back to top

## variablep

The 'variablep' macro tests if a Lisp expression evaluates to a symbol with a valid variable value bound to it in the current global or lexical environment:

    (defmacro variablep (expr)
      `(and (symbolp ,expr)
            (valuep ,expr)))

Depends on valuep, see and, defmacro, symbolp.

Back to top

## functionp

The 'functionp' macro tests if a Lisp expression eveluates to a function or a symbol with a valid function value bound to it in the current global or lexical environment:

    (defmacro functionp (expr)
      `(case (type-of ,expr)
         (closure (eq 'lambda (car (get-lambda-expression ,expr))))
         (subr    t)
         (symbol  (and (or (lfboundp ,expr) (fboundp ,expr))
                       (functionp (function ,(if (consp expr) (cadr expr) expr)))))
         (t       nil)))

Depends on lfboundp, see and, cadr, car, case, closure, defmacro, eq, fboundp, function, get-lambda-expression, lambda, nil, or, subr, symbol, t , type-of.

The awkward (function ,(if (consp expr) (cadr expr) expr)) construct is necessary because the function special form needs a pre-evaluated argument, what must be done at macro-expansion time, so an additional consp test is needed if the 'expr' argument is a list at all, otherwise cadr will produce an error.

Examples:

    (functionp #'car)  => T    ; subr = built-in function
    (functionp  'car)  => T    ; symbol with a function value

    (functionp #'and)  => NIL  ; fsubr = built-in special form
    (functionp "and")  => NIL  ; string

    (defun a () nil)   => A    ; closure = user-defined function
    (functionp #'a)    => T    ; closure
    (functionp  'a)    => T    ; symbol with a function value

    (setq b #'a)       => A    ; function A stored in variable B
    (fboundp 'b)       => NIL  ; no function B found
    (fboundp b)        => T    ; variable B evaluates to function A

    (functionp #'(lambda () nil))  => T    ; closure
    (functionp  '(lambda () nil))  => NIL  ; list
    (functionp   (lambda () nil))  => T    ; closure

    (functionp #'functionp)        => NIL  ; macro

    (let ((x nil))        ; lexical variable
      (functionp x))
    => NIL

    (flet ((y () nil))    ; lexical closure
      (functionp y))
    => T

    (labels ((z () nil))  ; lexical closure
      (functionp z))
    => T

Back to top

## specialp

    (defmacro specialp (expr)
      `(case (type-of ,expr)
         (fsubr   t)
         (symbol  (and (or (lfboundp ,expr) (fboundp ,expr))
                       (functionp (function ,(if (consp expr) (cadr expr) expr)))))
         (t       nil)))

Back to top

## macrop

    (defmacro macrop (expr)
      `(case (type-of ,expr)
         (closure (eq 'macro (car (get-lambda-expression ,expr))))
         (symbol  (and (or (lfboundp ,expr) (fboundp ,expr))
                       (macrop (function ,(if (consp expr) (cadr expr) expr)))))
         (t       nil)))

Back to top

## subrp

The 'subrp' function returns T if the symbol is a build-in function.

    (defun subrp (symbol)
      (eq 'subr (type-of symbol)))

Back to top

## fsubrp

The 'fsubrp' function returns T if the symbol is a build-in special function.

    (defun fsubrp (symbol)
      (eq 'fsubr (type-of symbol)))

Back to top

## closurep

The 'closurep' function returns T if the symbol is a user-defined function.

    (defun closurep (symbol)
      (eq 'closure (type-of symbol)))

Back to top

Nyquist / XLISP 2.0 - Contents | Tutorials | Examples | Reference