(defun prefix (a y) (cond ((null y) nil)
(t (cons (cons a (car y)) (prefix a (cdr y))))))
(setq result prefix(a (cons 1 2)))
(print result)
这个函数cdr通过列表y,递归地打印(a(car y))。如果P是第一个参数,并且y是列表(1 2 3),则它应该返回((P1)(P2)(P3))。但是,当我尝试给它参数并执行它时,我无法使该函数工作。这里有什么不对?
答案 0 :(得分:3)
这个函数cdr通过列表y,递归打印(a(car y))。
怎么打印什么?函数中没有单个print语句。
如果P是第一个参数,y是列表(1 2 3),它应该返回((P1)(P2)(P3))。
从查看代码开始,它将返回((P . 1) (P . 2) (P . 3))
而不是((P1) (P2) (P3))
。
但是,当我尝试给它参数并执行它时,我无法使该函数工作。这里有什么不对?
你的电话看起来不对劲。 prefix( ... )
有些东西看起来不像Lisp。在Lisp中,调用函数的语法是(prefix ... )
。函数名称位于左括号后面。
(defun prefix (a y)
(cond ((null y) nil)
(t (cons (cons a (car y))
(prefix a (cdr y))))))
(setq result prefix(a (cons 1 2))) ; this line has problems
(print result)
答案 1 :(得分:1)
请查看introductory lisp texts可用before您做其他事情。
[dons code-review hat]
(defun prefix (a y) (cond ((null y) nil)
(t (cons (cons a (car y)) (prefix a (cdr y))))))
(setq result prefix(a (cons 1 2)))
(print result)
首先,这些定义不符合您的散文描述所说的;作为递归函数的一部分,您没有任何打印。您打印result
,但是在prefix
ed列表完整地放在一起之后。您的prefix
函数也不会返回新符号,而是返回对。
无需设置中间值即可打印它们; Lisp函数隐式返回,可以在没有setq
(defun prefix (a y)
(cond ((null y) nil)
(t (cons (cons a (car y))
(prefix a (cdr y))))))
(print prefix(a (cons 1 2)))
Lisp完全是前缀标记,函数名称出现在调用括号内。
...
(print (prefix a (cons 1 2)))
a
来电中的 prefix
是一个未绑定的变量。我认为您要么使用“a
符号'a
”,要么使用“a
”,即:a
。如果您只是传递a
,Lisp将尝试将该名称作为变量进行评估,如果您没有为其分配值,则会失败。
...
(print (prefix 'a (cons 1 2)))
prefix
的第二个参数不是正确的列表;这是一对。为了看到差异,你需要看一下两种结构的底层指针结构。
(cons 1 2) => [ 1 | 2 ]
(list 1 2) => [ 1 | ]
\
[ 2 | ]
\
NIL
如果您尝试使用函数期望正确列表的对,则会得到错误#<TYPE-ERROR expected-type: LIST datum: 2>
,因为对的尾部不是列表,而{{1}的尾部} 是。
list
此时,你已经有了一个可运行的程序。在定义该函数后,在REPL中评估(defun prefix (a y)
(cond ((null y) nil)
(t (cons (cons a (car y))
(prefix a (cdr y))))))
(print (prefix 'a (list 1 2)))
应该会给你
(print (prefix 'a (list 1 2)))
请注意,我们有重复的输出;这是因为Lisp REPL会自动打印您评估的任何表单的返回值,这意味着您实际上可以完全删除CL-USER> (print (prefix 'a (list 1 2)))
((A . 1) (A . 2))
((A . 1) (A . 2))
。
print
为了做你想说的事情(用第一个参数作为前缀创建一个新的符号列表),你实际上需要使用一些字符串操作和CL-USER> (prefix 'a (list 1 2))
((A . 1) (A . 2))
来创建符号。
intern
(defun prefix (a y)
(cond ((null y) nil)
(t (cons (intern (format nil "~a~a" a (car y)))
(prefix a (cdr y))))))
现在应该返回(prefix 'a (list 1 2))
。请注意,Common Lisp不区分大小写,自动将小写符号转换为大写。
递归是一个很好的学习工具,尾递归是Scheme中的主要迭代构造,但如果可以的话,迭代地做事情通常是个好主意。请注意,CL不保证尾调优化,因此这通常意味着在某些情况下使用(A1 A2)
或loop
(或mapcar
)。
dolist
这些将为您提供与递归版本相同的输出,但如果您为它们提供足够长的列表,则不会有与堆栈空间不足相同的风险。
(defun iterative-prefix (a a-list)
(loop for elem in a-list
collect (intern (format nil "~a~a" a elem))))
(defun map-prefix (a a-list)
(mapcar
(lambda (elem) (intern (format nil "~a~a" a elem)))
a-list))
答案 2 :(得分:0)
两条评论:
首先,cons返回一个新的cons单元格,其中第一个参数位于cons中,第二个参数位于单元格的cdr中。 所以(缺点1 2)创建了一个新的缺陷单元(1.2),这就是你所看到的。
如果你想让结果成为列表(1 2),那么第二个参数必须是一个列表:(cons 1'(2))
其次,你写了一些相当难看的C风格的Lisp代码。考虑:
(defun prefix (a y)
(if ((null y) nil)
(cons (cons a (car y)) (prefix a (cdr y)))))
(print (prefix a '( 1 2))))
注意:不要创建仅在以下行中使用的变量。正确布局代码(人们在阅读Lisp时不解析括号,它们依赖于传统布局)。如果只有一个测试加上默认值(即if / then / else),则使用if而不是cond。
您的代码仍然有错误(我还没有修复)。看起来你实际上并没有在REPL中编写这段代码 - 如果你这样做,你会发现编写Lisp代码要容易得多。这是Lisp优于Algol语言的一大优势。