0

I am trying to define my own function to make my hw2 easier but it is not working. Could you take a look at it and tell me what I am missing?

    (DEFUN testAL(x)
        COND ( ( ATOMP(x) ) 'this-is-an-atom )
             ( ( LISTP(x) ) 'this-is-a-list )
             ( T 'this-is-neither ) )

I want this conditional function to take an input X and output if it is an atom, list, or neither. Problem is that when I input NIL, I get an error: Attempt to take the value of the unbound variable `COND'.

Homework 2 consists of the following question:

Which of the following are atoms, which lists, which both and witch neither?

a. nil

b. (expt 10 3)

c. (a b)

d. 64

e. T

f. (No place like home)

g. ‘(+ 3 5 6)

4

1 回答 1

6

Your parenthesis are not in the correct places. A parenthesis, unless quoted, are the start of a function application.

It begins with a variable cond that is not bound. It's not the special form (cond (predicate consequent) (predicate2 consequent2)) since it doesn't start with an open parenthesis.

From indentation alone I guess you meant to write:

(DEFUN testAL (x)
    (COND ((ATOM x) 'this-is-an-atom)
          ((LISTP x) 'this-is-a-list)
          (T 'this-is-neither)))

(testal 'test)    ; ==> THIS-IS-AN-ATOM
(testal '(a b c)) ; ==> THIS-IS-A-LIST

I have removed the extra parenthesis around x since (x) means apply the function x while x means the variable x. With x in a different position like (+ x 3) then + is the function to be applied and x is one of its operands.

I changed atomp to atom. Since atom is one of the very first primitives defined with the very first LISP in the 50's, it does not have a postfix p like most other predicates.

Edit: Multiple match

You could just have several cond (or if since you only have one test in each) and do side effects like (print "THIS-IS-AN-ATOM") since your base case will never trigger (nothing is neither list nor atom in CL). This is perhaps the easies solution.

(DEFUN testAL (x)
    (if (ATOM x) (print 'this-is-an-atom))
    (if (LISTP x) (print 'this-is-a-list)))

(testal '()) ; ==> THIS-IS-A-LIST (but prints both)

For a more functional approach I would have done it with higher order functions keeping the code testable and supply a print-function that does the side effects. Be aware that this might not be as easy to read for a beginner:

;; a list of pairs of predicate and their desription
(defparameter *type-predicates-and-description* 
                '((douglasp . this-is-the-answer-to-everything)
                  (floatp . this-is-a-floating-pont-number)
                  (integerp . this-is-an-integer)
                  (numberp . this-is-a-number)
                  (null . this-is-null)
                  (listp . this-is-a-list)
                  (characterp . this-is-a-character)
                  (stringp . this-is-a-string)))

;; custom made predicate
(defun douglasp (x)
  (and (numberp x) (= x 42)))

;; returns all the types of a particular value  
(defun get-type-info (x)
  "return a list if types thet describes argument"
  (flet ((check-type (acc type-pair)
            "Accumulate description when predicate match"
            (if (funcall (car type-pair) x) 
                (cons (cdr type-pair) acc) 
                 acc))) 
    ;; test x for each type predicate-description        
    (let ((res (reduce #'check-type
                       *type-predicates-and-description* 
                       :initial-value '())))
      ;; check of empty list (no types matched)
      (if (null res) 
          (list 'this-is-neither) 
      res))))

;; test it
(get-type-info '()) ; ==> (THIS-IS-A-LIST THIS-IS-NULL)
(get-type-info 42)  ; ==> (THIS-IS-A-NUMBER 
                    ;      THIS-IS-AN-INTEGER 
                    ;      THIS-IS-THE-ANSWER-TO-EVERYTHING)
(get-type-info #()) ; ==> (THIS-IS-NEITHER)

;; Make a function to do side effects
(defun print-type-info (x)
  (format t "~{~a~^, ~}." (get-type-info x)))

(print-type-info '()) ; ==> NIL
                      ; and prints "THIS-IS-A-LIST, THIS-IS-NULL."
于 2013-09-05T23:54:16.197 回答