Duarte P
Duarte P

Reputation: 154

Accessing structure fields from the structure itself in Common LISP

For my project, I specifically need a structure that has (among other things) 2 slots:

That function slot must evaluate the current-state and return a result based on it. However, I can't find how to do this properly. Here's a segment of my code.

(defstruct state moves-left)

(defstruct problem
    (current-state)
    (solution (function (lambda () (null (state-moves-left :current-state)))))
)

No errors on compiling, but they happen when I interpret this:

> (setq p0 (make-problem :current-state (make-state)))
> (funcall (problem-solution p0))

SYSTEM::%STRUCTURE-REF: :CURRENT-STATE is not a structure of type STATE

Anyone knows how to solve this? I usually just use common functions, but these structure and slots are hard requirements.

EDIT: thanks for the answers. After learning this was impossible, I reread the requirements more thoroughly and posted the answer here.

Upvotes: 3

Views: 1230

Answers (3)

Duarte P
Duarte P

Reputation: 154

After learning this was impossible, I reread the requirements more thoroughly and found out this function will actually receive an argument (a state). So, the code now works:

(defstruct problem
    (current-state)
    (solution (function (lambda (state) (not (null (state-moves-left state))))))
)

Upvotes: 0

Rainer Joswig
Rainer Joswig

Reputation: 139261

You could have a separate create function:

(defun create-problem (state)
  (let ((problem (make-problem :current-state state)))
    (setf (problem-solution problem)
          (lambda ()
            (null (state-moves-left (problem-current-state problem)))))
    problem))

But: Why not use a function/method directly?

(defmethod problem-solution ((p problem))
  (null (state-moves-left (problem-current-state p))))

Upvotes: 5

Renzo
Renzo

Reputation: 27424

The reason for the error is that structures in Common Lisp cannot be used as classes: inside the function default value of the slot solution there is no way of referring to the slots of the structure itself (as you are trying to do with (state-moves-left :current-state).

If you insist in using structures instead of classes, one possibility is to define the function with a parameter, and pass the structure itself when the function is called. Something like:

(defstruct problem
    (current-state)
    (solution (function (lambda (p) (null (state-moves-left p))))))

(let ((p0 (make-problem :current-state (make-state))))
  (funcall (problem-solution p0) p0))

Upvotes: 3

Related Questions