Log*_*der 0 lisp lambda common-lisp
我最近一直在尝试学习 Common Lisp,这是我使用过的任何编程语言中最痛苦和最缓慢的学习过程。真的很烦我。即使 Notepad++ 显示括号对应什么,它仍然很痛苦。
我一直在尝试编写一个模拟库数据库的程序。我一直被告知"SYSTEM::%EXPAND-FORM: (NULL L) should be a lambda expression"- 我在 Stack Overflow 上读过其他帖子,说这与使用太多括号有关,但是在使用语法一个多小时后,没有任何效果。我希望你们中一些更有经验的 LISP 程序员能够看到我希望是新手的错误。谢谢你。代码如下。
(setq library nil)
(defun add_book(bookref title author publisher)
(setf (get bookref 'title) title)
(setf (get bookref 'author) author)
(setf (get bookref 'publisher) publisher)
(setq library (cons bookref library))
bookref)
(defun retrieve_by (property my_value)
(setq result nil)
(do ((L library (cdr L)))
(cond
((NULL L) result)
(equal (get (car L) property) my_value)
(cons (car L) result))))
Run Code Online (Sandbox Code Playgroud)
您的代码缩进更好,如下所示:
(defun retrieve_by (property my_value)
(setq result nil)
(do ((L library (cdr L)))
(cond
((NULL L) result)
(equal (get (car L) property) my_value)
(cons (car L) result))))
Run Code Online (Sandbox Code Playgroud)
do的语法是:
do ({var | (var [init-form [step-form]])}*)
(end-test-form result-form*)
declaration*
{tag | statement}*
Run Code Online (Sandbox Code Playgroud)
这给了我们一个提示,您的cond位置错误,并且预期是一个以结束测试形式作为其第一个元素的列表:
(defun retrieve_by (property my_value)
(setq result nil)
(do ((L library (cdr L))) ; iterating L
((NULL L) result) ; end test + result
(if (equal (get (car L) property) my_value)
(push (car L) result))))
Run Code Online (Sandbox Code Playgroud)
你为什么看到那个错误信息?
"SYSTEM::%EXPAND-FORM: (NULL L) should be a lambda expression"
(do ((L library (cdr L))) ; iterating
(cond ((NULL L) result) ...) ; end-test + result forms
Run Code Online (Sandbox Code Playgroud)
Lisp 期望在第一个位置有一个测试和结果形式的列表:
(cond ; the test is just a variable reference
((NULL L) result) ; result form number one
...)
Run Code Online (Sandbox Code Playgroud)
现在测试看起来仍然有效,但第一个结果形式不是:
((NULL L) result)
Run Code Online (Sandbox Code Playgroud)
Common Lisp 中不允许将列表作为表单的第一个元素——除了一个例外:一个 lambda 表达式:
((lambda (a b) (+ a b 10)) 12 20)
Run Code Online (Sandbox Code Playgroud)
因此,您的 Lisp 实现抱怨这(null l)不是 lambda 表达式。在这里,我认为可以在实现中改进错误消息...
更多反馈
还有一个问题:result是一个未定义的变量。我们需要创建一个局部变量result。这是通过以下方式完成的let:
(defun retrieve_by (property my_value)
(let ((result nil))
(do ((L library (cdr L)))
((NULL L) result)
(if (equal (get (car L) property) my_value)
(push (car L) result)))))
Run Code Online (Sandbox Code Playgroud)
另一个问题:library是一个全局变量。这些写成*library*并由DEFPARAMETERor定义DEFVAR:
(defvar *library* nil)
(defun add_book (bookref title author publisher)
(setf (get bookref 'title) title)
(setf (get bookref 'author) author)
(setf (get bookref 'publisher) publisher)
(setq *library* (cons bookref *library*))
bookref)
(defun retrieve_by (property my_value)
(let ((result nil))
(do ((L *library* (cdr L)))
((null L) result)
(if (equal (get (car L) property) my_value)
(push (car L) result)))))
Run Code Online (Sandbox Code Playgroud)
下一个改进是文体:代码大多以小写形式编写,不使用下划线。而是使用连字符:
(defvar *library* nil)
(defun add-book (bookref title author publisher)
(setf (get bookref 'title) title)
(setf (get bookref 'author) author)
(setf (get bookref 'publisher) publisher)
(setq *library* (cons bookref *library*))
bookref)
(defun retrieve-by (property my_value)
(let ((result nil))
(do ((list *library* (cdr list)))
((null lisp) result)
(if (equal (get (car list) property) my_value)
(push (car list) result)))))
Run Code Online (Sandbox Code Playgroud)
下一个改进是风格:car并且cdr是老式的,用于 cons 单元操作。如果我们处理列表,我们使用firstand rest。
这是现在我们的代码:
(defvar *library* nil)
(defun add-book (bookref title author publisher)
(setf (get bookref 'title) title)
(setf (get bookref 'author) author)
(setf (get bookref 'publisher) publisher)
(push bookref *library*)
bookref)
(defun retrieve-by (property my-value)
(let ((result nil))
(do ((list *library* (rest list)))
((null list) result)
(if (equal (get (first list) property) my-value)
(push (first list) result)))))
Run Code Online (Sandbox Code Playgroud)
我们可以试试:
CL-USER 151 > (add-book 'johann-holtrop "Johann Holtrop" "Rainald Goetz" "Suhrkamp")
JOHANN-HOLTROP
CL-USER 152 > (retrieve-by 'title "Johann Holtrop")
(JOHANN-HOLTROP)
Run Code Online (Sandbox Code Playgroud)
简化代码
Common Lisp 有一种更简单的形式来迭代一个列表:dolist:
(defun retrieve-by (property my-value)
(let ((result nil))
(dolist (bookref *library* result)
(if (equal (get bookref property) my-value)
(push bookref result)))))
Run Code Online (Sandbox Code Playgroud)
Common Lisp 还具有查找项目的功能。一个奇怪的选择是remove与:test-not参数一起使用。通过查看我们正在提取的键值,我们保留所有满足我们测试的项目:
(defun retrieve-by (property my-value)
(remove my-value *library*
:test-not #'equal
:key (lambda (bookref)
(get bookref property))))
Run Code Online (Sandbox Code Playgroud)
风格规则
重复上面的样式规则:
*variable-name*retrieve-bydo运算符更容易使用| 归档时间: |
|
| 查看次数: |
211 次 |
| 最近记录: |