Christopher Vetter
Christopher Vetter

Reputation: 1

Lisp - Type Error bug simple program

So the following is my code in lisp and I am using emacs

(defun eval-var (var state)
  (cond (( atom state) nil)
        ((eql(caar state) var) (cadr (car state)));;(caar state))
        ((eval-var var (cdr state))) ) )

(defvar *clause* '( (not a) (not b) c))

(defvar *state*  '( (a t) (b t) (c t) (d t) ))

(defun eval-clause (clause state)
  (let ((d (cond ((if (equal (car clause) 'a) (eval-var (car clause) state) (not(eval-var (cadr (car clause)) state)))) ))
        (e (cond ((if (equal (cadr clause) 'b) (eval-var (cadr clause) state) (not(eval-var (cadr  (car clause)) state)))) ))
        (f (cond ((if (equal (caddr clause) 'c) (eval-var (caddr clause) state) (not(eval-var (caddr (car clause)) state)))) )) )
    (if (equal d e) t nil )))

Below is when I tried to run the functions.

* (load "3sat.lisp")

; Loading #P"/Network/Servers/fs.labs.encs/Volumes/raid1/users_a/vetterc7/Desktop/wsu16/cs355/3sat/3sat.lisp".
T
* (eval-clause *clause* *state*)

; Note: Variable F defined but never used.
;
T
* *clause*

((NOT A) (NOT B) C)
* clause

(A (NOT B) C)
* (eval-clause clause *state*)


Type-error in KERNEL::OBJECT-NOT-LIST-ERROR-HANDLER:  A is not of type LIST
   [Condition of type TYPE-ERROR]

Restarts:
  0: [ABORT] Return to Top-Level.

Debug  (type H for help)

(CADR 1 A)[:EXTERNAL]
Source: Error finding source:
Error in function DEBUG::GET-FILE-TOP-LEVEL-FORM:  Source file no longer exists:
  target:code/list.lisp.
0]

I was hoping that someone could help me out and explain why im getting this error and what I need to do to correct it.

Upvotes: 0

Views: 425

Answers (2)

jkiiski
jkiiski

Reputation: 8411

It seems like what you're trying to achieve is to evaluate a set of logical expressions in *clause* using variables from *state*. Your current code is kinda messy, so I just wrote a solution myself instead of fixing it.

I used a library called Optima for pattern matching. You can install it with quicklisp by running (ql:quickload :optima) before loading the below code.

;; My solution supports NOT, AND and OR operators. AND and OR can only
;; be used with exactly two arguments. These will be evaluated
;; recursively, so they can be nested too.
(defparameter *clause* '((or b c)
                         (not b)
                         (or c (and a b))))

;; I used cons cells here instead of lists. More efficient this way.
;; You can use CAR and CDR to access the parts of a cons cell. Note
;; that accessing the second part is done with just a CDR, rather than
;; with CADR like with lists.
(defparameter *state* '((a . t)
                        (b . t)
                        (c . nil)
                        (d . nil)))

(defun get-var (var state)
  "Get VAR in STATE. Signals an error if VAR doesn't exist."
  ;; You can use ASSOC to find values in an "association list" like
  ;; *STATE*. ASSOC returns the whole cons, so CDR is used to return
  ;; the value of the variable.
  (cdr (or (assoc var state)
           (error "Unknown variable ~a." var))))

(defun eval-clause (clause state)
  "Recursively evaluate CLAUSE using variables in STATE."
  ;; OPTIMA:MATCH performs pattern matching with the first argument
  ;; (CLAUSE in this case). Pattern matching is much like a CASE,
  ;; except it allows you to match against various kinds of patterns
  ;; instead of simple values.
  (optima:match clause
    ;; This matches a single atom (such as A or B) and returns its
    ;; value.
    ((optima:guard var (atom var)) (get-var var state))
    ;; The patterns like `(LIST 'AND a b)` match a list that starts
    ;; with AND and has two elements after it; the two elements will
    ;; be bound to variables A and B, which can then be used in the
    ;; following form.
    ((list 'not a) (not (eval-clause a state)))
    ((list 'and a b) (and (eval-clause a state)
                          (eval-clause b state)))
    ((list 'or a b) (or (eval-clause a state)
                        (eval-clause b state)))
    ;; If CLAUSE doesn't match anything above, signal an error.
    (err-form (error "Unknown expression: ~a." err-form))))

(defun eval-all-clauses (clauses state)
  "Evaluate all logical expressions in CLAUSES using variables in STATE.
Returns a list of results."
  (mapcar (lambda (c) (eval-clause c state)) clauses))

;; Run it
(eval-all-clauses *clause* *state*)
; => (T NIL T)

Upvotes: 0

Rainer Joswig
Rainer Joswig

Reputation: 139251

If you use SBCL you can see the source where the error happens.

The code needs to be compiled with a higher debug value:

(declaim (optimize (debug 3)))

Example:

CL-USER> (eval-clause '(A (NOT B) C) *state*)

debugger invoked on a TYPE-ERROR: The value A is not of type LIST.

Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.

restarts (invokable by number or by possibly-abbreviated name):
  0: [RETRY            ] Retry SLIME REPL evaluation request.
  1: [ABORT            ] Return to SLIME's top level.
  2: [REMOVE-FD-HANDLER] Remove #<SB-IMPL::HANDLER INPUT on descriptor 12: #<CLOSURE (LABELS SWANK-BACKEND::RUN :IN SWANK-BACKEND:ADD-FD-HANDLER) {1004DC423B}>>
  3:                     Exit debugger, returning to top level.
(EVAL-CLAUSE (A (NOT B) C) ((A T) (B T) (C T) (D T)))
   source: (CADR (CAR CLAUSE))

You can find out about the source:

0] source

(CADR (CAR CLAUSE)) 

You can't call CAR on a symbol A.

One more enclosing form:

0] source 1

(EVAL-VAR (#:***HERE*** (CADR (CAR CLAUSE))) STATE) 

Two more enclosing forms:

0] source 2

(NOT (EVAL-VAR (#:***HERE*** (CADR (CAR CLAUSE))) STATE)) 

0] source 3

(IF (EQUAL (CADR CLAUSE) 'B)
    (EVAL-VAR (CADR CLAUSE) STATE)
    (NOT (EVAL-VAR (#:***HERE*** (CADR (CAR CLAUSE))) STATE))) 

You now see the form where it happens in enough context.

Upvotes: 3

Related Questions