hi - I am trying to learn cl. This is what I did for an exercise in Nick Levine's
lecture notes (the end of week 7, as pointed to in somewhere like alu):
(defun make-student-db ()
;; store a crude database of students and modules in a closure
;; it is accessed by functions returned by values, to be used by e.g.
;; multiple-value-setq *clear* *update-students* .. etc
(defstruct student
name
SID ; an integer
modules)
(defstruct module
title
mid
students)
(let ((roll ())
(high-sid 0)
(high-mid 0)
(modules ()))
(flet ((prompt-for-student ()
(format t "~&~A~%" "Please enter a new student name or newline to end")
(read-line))
(prompt-for-module ()
(format t "~&~A~%" "Please enter a module name or newline to end")
(read-line))
(find-student (sid)
"Find a student from his sid"
(dolist (elem roll) (if (= (student-sid elem) sid) (return elem))))
(find-module (mid)
"Find a module from its id"
(dolist (elem modules) (if (= (module-mid elem) mid) (return elem)))))
(values
#'(lambda ()
"clear the database"
(setf roll () modules () high-sid 0 high-mid 0))
#'(lambda ()
"update student roll"
(do ((newname (prompt-for-student)(prompt-for-student))) ((string= newname ""))
(push (make-student :name newname :sid (incf high-sid)) roll)
(setf roll (sort roll #'string< :key #'student-name))))
#'(lambda ()
"update modules list"
(do ((newtitle (prompt-for-module)(prompt-for-module))) ((string= newtitle ""))
(push (make-module :title newtitle :mid (incf high-mid)) modules)
(setf modules (sort modules #'string< :key #'module-title))))
#'(lambda (sid mid)
"Enrol a student on a course module"
(push mid (student-modules (find-student sid)))
(push sid (module-students (find-module mid))))
#'find-student
#'find-module
#'(lambda ()
"Print students"
(dolist (elem roll) (print elem)))
#'(lambda ()
"Print modules"
(dolist (elem modules) (print elem)))))))
This works perfectly in cmucl, but lispworks produces compilation errors
viz:
The following functions are undefined:
STUDENT-MODULES which is referenced by MAKE-STUDENT-DB
MAKE-STUDENT which is referenced by MAKE-STUDENT-DB
MODULE-STUDENTS which is referenced by MAKE-STUDENT-DB
STUDENT-SID which is referenced by MAKE-STUDENT-DB
MAKE-MODULE which is referenced by MAKE-STUDENT-DB
(SETF STUDENT-MODULES) which is referenced by MAKE-STUDENT-DB
MODULE-MID which is referenced by MAKE-STUDENT-DB
(SETF MODULE-STUDENTS) which is referenced by MAKE-STUDENT-DB
; Loading fasl file /home/will/zx/dev/temp/make-student-db.ufsl
; Loading fasl file /home/will/lwl/lib/4-1-0-0/modules/concat/xref.ufsl
It doesn't seem to like the default accessor names, however, it produces an
output file and then mostly works -
CL-USER 3 : 1 > (multiple-value-setq (clear update-students update-modules enrol find-student find-module print-students print-modules)(make-student-db))
#<closure (SUBFUNCTION 1 MAKE-STUDENT-DB) 212B073A>
CL-USER 4 : 1 > (funcall clear)
0
......
CL-USER 7 : 1 > (funcall print-students)
#S(STUDENT NAME "fred" SID 3 MODULES NIL)
#S(STUDENT NAME "rose" SID 2 MODULES NIL)
#S(STUDENT NAME "will" SID 1 MODULES NIL)
NIL
CL-USER 8 : 1 > (funcall print-modules)
#S(MODULE TITLE "cornflakes" MID 4 STUDENTS NIL)
#S(MODULE TITLE "english" MID 3 STUDENTS NIL)
#S(MODULE TITLE "french" MID 2 STUDENTS NIL)
#S(MODULE TITLE "history" MID 1 STUDENTS NIL)
NIL
but
CL-USER 11 : 1 > (funcall enrol 1 1)
Error: Undefined function (SETF STUDENT-MODULES) called with arguments ((1) #S(STUDENT NAME "will" SID 1 MODULES NIL)).
Can anyone explain what I have got wrong, and why the compilers differ.
Thanks in advance
On Wed, 13 Aug 2003 17:59:10 +0100, Will White
<··········@ntlworld.com> wrote:
>
>hi - I am trying to learn cl. This is what I did for an exercise in Nick Levine's
>lecture notes (the end of week 7, as pointed to in somewhere like alu):
>
>(defun make-student-db ()
> ;; store a crude database of students and modules in a closure
> ;; it is accessed by functions returned by values, to be used by e.g.
> ;; multiple-value-setq *clear* *update-students* .. etc
> (defstruct student
> name
> SID ; an integer
> modules)
> (defstruct module
> title
> mid
> students)
>
>
>The following functions are undefined:
>STUDENT-MODULES which is referenced by MAKE-STUDENT-DB
>MAKE-STUDENT which is referenced by MAKE-STUDENT-DB
>MODULE-STUDENTS which is referenced by MAKE-STUDENT-DB
>STUDENT-SID which is referenced by MAKE-STUDENT-DB
>MAKE-MODULE which is referenced by MAKE-STUDENT-DB
>(SETF STUDENT-MODULES) which is referenced by MAKE-STUDENT-DB
>MODULE-MID which is referenced by MAKE-STUDENT-DB
>(SETF MODULE-STUDENTS) which is referenced by MAKE-STUDENT-DB
>
>
>
>Can anyone explain what I have got wrong, and why the compilers differ.
>
I suspect that your problem lies in having your DEFSTRUCT definitions
inside the DEFUN.
DEFSTRUCT definitions are global; putting them inside the DEFUN isn't
going to make them local to that function.
Take them out of the DEFUN and see if it all works.
Let's reduce this to a simpler form:
(compile (defun foo ()
(defstruct foo bar)
(setf (foo-bar (make-foo)) nil)))
-> (LispWorks) "The following function is undefined: (SETF FOO-BAR)
which is referenced by FOO"
The spec says <http://www.lispworks.com/reference/HyperSpec/Body/m_defstr.htm>:
"If a defstruct form appears as a top level form, the compiler must
... make the structure slot readers known to setf."
However, the defstuct here is not at top-level. Section 3.2.3.1.1
(Processing of Defining Macros)
<http://www.lispworks.com/reference/HyperSpec/Body/03_bcaa.htm> says:
"... these compile-time side effects happen only when the defining macros
appear at top level."
So it might actually be the case that cmucl is wrong, and Lispworks is
correct in not performing the side-effect of making the structure slot
reader for FOO-BAR known to setf.
(Erm, have I got this right?)
- nick
···@ravenbrook.com (Nick Levine) writes:
> Let's reduce this to a simpler form:
>
> (compile (defun foo ()
> (defstruct foo bar)
> (setf (foo-bar (make-foo)) nil)))
>
> -> (LispWorks) "The following function is undefined: (SETF FOO-BAR)
> which is referenced by FOO"
> [...]
> (Erm, have I got this right?)
I think correctness of implementations' behaviour depends on how they
implement structure slot setters. CMUCL's DEFSTRUCT not at top level
is demonstrably non-conforming, as can be seen by the following:
(defun foo ()
(if *some-boolean*
(defstruct foo a)
(defstruct foo a b)))
just compiling that definition in CMUCL will cause all sorts of
errors. LispWorks is certainly justified in warning that the (SETF
FOO-BAR) function is undefined when it compiles FOO, because according
to ANSI the (SETF FOO-BAR) function need not be made known to the
compiler. Whether the FOO function then goes on to work when executed
depends on whether the implementation provides (setf foo-bar)
functions or a setf macro; if the latter, then FOO will cause an
undefined function error at runtime.
Christophe
--
http://www-jcsu.jesus.cam.ac.uk/~csr21/ +44 1223 510 299/+44 7729 383 757
(set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b)))
(defvar b "~&Just another Lisp hacker~%") (pprint #36rJesusCollegeCambridge)