使用带有remove-if-not的defstruct数据库

时间:2010-02-02 06:16:10

标签: elisp common-lisp

我正在尝试通过添加书中描述的 select - 函数来调整此defstruct示例:Practical Common Lisp。我正在使用Common Lisp包在Emacs中运行代码。 select-by-first 不会返回任何内容。在Lisp书中,作者不使用defstruct,所以我必须做一些稍微不同的事情?

(defun select-by-first (first-name)
  (remove-if-not
    #'(lambda (employee)
        (equal (getf employee :first-name) first-name))
    *emp-db*))

(select-by-first "steve")

完整的计划:

(require 'cl)
;; http://mypage.iu.edu/~colallen/lp/node56.html
;; http://www.gigamonkeys.com/book/practical-a-simple-database.html
;;
(defvar *emp-db* nil)
(defun add-record (emp) (push emp *emp-db*))

(defstruct employee
   age
   first-name
   last-name
   sex
   children)
(add-record (make-employee))

(add-record (make-employee
               :age 34
               :last-name 'farquharson
               :first-name 'alice
               :sex 'female))

(add-record (make-employee
               :age 43
               :last-name 'jobs
               :first-name 'steve
               :sex 'male))

(add-record (make-employee
               :age 53
               :last-name 'ballmer
               :first-name 'steve
               :sex 'male))
(defun select-by-first (first-name)
  (remove-if-not
    #'(lambda (employee)
        (equal (getf employee :first-name) first-name))
    *emp-db*))

(select-by-first "steve")

2 个答案:

答案 0 :(得分:4)

有一些基本的错误/问题。但只有两个小的改动,我们可以让你的例子在Common Lisp中工作。

  • Emacs Lisp的Common Lisp兼容包并不是一个真正的Common Lisp。通常最好使用真正的Common Lisp实现。 Emacs Lisp缺少一些难以模仿以使其与Common Lisp兼容的基本内容 - 例如词法闭包(更新2014,最新版本的GNU Emacs现在也支持词法闭包)。

  • 小改动:我改变了你的例子,以便数据库不包含史蒂夫乔布斯两次,但史蒂夫乔布斯和史蒂夫鲍尔默。

现在,我们需要改变什么才能使它在Common Lisp中运行?

  • (getf employee:first-name)应该是(员工名字员工)。 DEFSTRUCT宏自动生成这些访问器函数。在Common Lisp中,您无法使用GETF访问实际结构的字段。

  • 您的数据库有两个名为STEVE(符号)的对象,但您正在搜索名称“steve”(字符串)。 (等于'史蒂夫'史蒂夫“)是假的。通常,符号与字符串不相等。所以你应该搜索(先选择'steve)。

在LispWorks中:

CL-USER 11 > (select-by-first "steve")
NIL

CL-USER 12 > (select-by-first 'steve)
(#S(EMPLOYEE :AGE 53 :FIRST-NAME STEVE :LAST-NAME BALLMER :SEX MALE
             :CHILDREN NIL) 
 #S(EMPLOYEE :AGE 43 :FIRST-NAME STEVE :LAST-NAME JOBS :SEX MALE
             :CHILDREN NIL))

答案 1 :(得分:1)

谢谢Rainer。这是在Emacs中运行的已完成代码。

#!/usr/bin/emacs --script

;; Derived from code on these sites:
;;
;; http://mypage.iu.edu/~colallen/lp/node56.html
;; http://www.gigamonkeys.com/book/practical-a-simple-database.html
;;
(require 'cl)
(defvar *emp-db* nil)
(defun add-record (emp) (push emp *emp-db*))

(defstruct employee age first-name last-name sex children)

(add-record (make-employee))

(add-record (make-employee :age 34
      :last-name 'farquharson
      :first-name 'alice
      :sex 'female))

(add-record (make-employee :age 43
      :last-name 'jobs
      :first-name 'steve
      :sex 'male))

(add-record (make-employee :age 53
      :last-name 'ballmer
      :first-name 'steve
      :sex 'male))

(defun select-by-first (first-name)
  (remove-if-not
   #'(lambda (employee)
       (equal (employee-first-name employee) first-name))
   *emp-db*))

(defun select-by-last (last-name)
  (remove-if-not
   #'(lambda (employee)
       (equal (employee-last-name employee) last-name))
   *emp-db*))

(princ "Employees with the first name Steve:\n")
(princ "  ") 
(princ (select-by-first 'steve))
(princ "\n")
(princ "Employees with the last name Jobs:\n")
(princ "  ")
(princ (select-by-last 'jobs))
(princ "\n")