尝试以Lisp递归方式打印三角形。我溢出,但是我不知道从哪里来。请注意,我是Lisp编程的新手。
(defun triangle (n)
(if (not (oddp n))(progn
(print "This is not an odd integer")
(return-from triangle n)))
(if (< n 1) '())
(setf lst (cons (car(list n)) (triangle (- n 2))))
(print lst))
(三角形7)
答案 0 :(得分:2)
让我们回顾一下代码的某些部分。
(if (not (oddp n)) (progn (print ...) (return-from ...)))
当if
仅具有一个分支时,请考虑使用when
或unless
,尤其是
如果您在子表单中放置了progn
。例如,您可以通过切换来摆脱progn
到when
:
(when (not (oddp n))
(print ...)
(return-from ...))
(when (not ...))
表达式与(unless ...)
相同:
(unless (oddp n)
...)
在这里,您将输出一条错误消息,然后从函数中返回。
Common Lisp有例外,这些例外是针对那些用例的。
您通常会致电(error "Not an odd integer: ~d" n)
,
但是在这里您可以依靠assert
的默认行为,并且
将整个支票替换为:
(assert (oddp n))
如果尝试使用2,您将获得一条错误,并显示类似以下消息:
The assertion (ODDP N) failed with N = 2.
足够进行测试了。
然后,您具有以下表达式:
(cons (car (list n)) (triangle (- n 2)))
写(list e1 e2 .. en)
时,就像写了一样:
(cons e1 (cons e2 (... (cons en nil))))
在您的情况下,这意味着(list n)
与以下内容相同:
(cons n nil)
但是自从您执行以下操作后,
(car (cons n nil))
实际上,您只是在分配一个单元并丢弃它只是为了访问n
。
整个表达式可以替换为n
。
第三,您还对setf
使用lst
,其中lst
是未定义的变量。
在大多数实现中(但实际上未指定此行为),这将设置全局绑定
对于lst
而言,从函数内部设置全局变量是一种不好的做法。
您可以改用let
:
(let ((lst (cons n (triangle (- n 2)))))
(print lst))
但是该变量仅使用一次,您也可以内联它:
(print (cons n (triangle (- n 2))))
最后,您拥有:
(defun triangle (n)
(assert (oddp n))
(if (< n 1)
()
(print (cons n (triangle (- n 2))))))
这是样式问题,但是请记住,通常可以替换在其分支之一中返回if
的{{1}}
由nil
或when
(此处为unless
)创建。有些人不喜欢这样,更喜欢不依赖unless
和nil
的{{1}}返回值。
无论如何,让我们对其进行测试:
when
给出:
unless
请注意列表如何向后移动。
解决问题的一种方法是将(triangle 7)
替换为(1)
(3 1)
(5 3 1)
(7 5 3 1)
,但这是行不通的。你知道为什么吗?
相反,让我们向后构建列表,该列表需要从1开始向上计数,直到达到(print ...)
:
(print (reverse ...))
由于第二个参数是可选的,因此我们可以像以前一样调用它:
n
但是现在,输出为:
(defun triangle (n &optional (c 1))
(assert (oddp n))
(when (<= c n)
(print
(cons c (triangle n (+ c 2))))))
答案 1 :(得分:1)
括号错误!根据您的缩进,我相信您需要以下内容:
(if (< n 1) '())
(setf ...
成为if-then-else,其中setf
在else分支中。为此,它应该看起来像:
(if (< n 1) '()
(setf ...
在当前设置中,始终评估setf
。
答案 2 :(得分:0)
一个有用的策略是将三角形的构建与显示分开。 这样,您可以更改打印格式,而无需更改生成三角形的代码。
让我们选择将三角形表示为列表列表
这样create-triangle 7 => ((1) (1 3) (1 3 5) (1 3 5 7))
。
以下实现生成所需的三角形:
(defun create-triangle (n)
(labels ((aux (x acc)
(if (> x n)
acc
(let* ((hd (car acc))
(new (append hd (list x))))
(aux (+ x 2) (cons new acc))))))
(when (and (plusp n) (oddp n))
(reverse (aux 1 nil)))))
注意事项:Lisp是一种面向表达式的语言 因此,通常,不需要返回类似的语句。
辅助功能aux
接受整数x
并
列表acc
。如果x
大于n
,则返回acc
否则,我们创建2个局部变量:hd
保存第一个列表
在我们的累加器中找到:这将是最新行
计算的。 new
由当前数字x
附加而成
到hd
。例如,如果acc = ((1 3 5) (1 3) (1))
和
x = 7
,然后hd = (1 3 5)
和new =
(1 3 5 7).
Having made this computation, we call aux with the new
x
bound to
x + 2 which is 7 in out example, and
acc bound to
( (1 3 5 7)(1 3 5)(1 3)(1)). This way we build the triangle
in reverse.
The function
创建三角形, first checks that
n is both positive and odd,
and when that is satisfied, it returns the reverse of the triangle
built by aux. Thus we get
((1)(1 3)(1 3 5 )(1 3 5 7))in our example.
If
n`不是正数和奇数,它只返回空列表。
如Coredump所述,您将其更改为进行错误检查。
现在我们有了三角形,剩下的就是打印三角形。 我们使用以下功能来做到这一点:
(defun print-triangle (xss)
(when xss
(format t "~&~{~a ~}" (car xss))
(print-triangle (cdr xss))))
print-triangle
有趣的部分是format
表达式。
t
表示输出为stdout
,通常为
屏幕,在控制字符串中; ~&
的意思是:确保我们换了一行,并且
~{~a ~}
打印列表的内容,并在它们之间留一个空格,
(car xss)
是格式参数。
现在我们可以将两个功能放在一起
(defun triangle (n)
(print-triangle (create-triangle n)))
快速测试:
CL-USER> (triangle 19)
1
1 3
1 3 5
1 3 5 7
1 3 5 7 9
1 3 5 7 9 11
1 3 5 7 9 11 13
1 3 5 7 9 11 13 15
1 3 5 7 9 11 13 15 17
1 3 5 7 9 11 13 15 17 19
NIL
答案 3 :(得分:0)
将问题分解成小块始终是一个好习惯,这种方法还使您的代码更具模块化,因此您可以更安全,灵活地更改部分代码。
首先,您可以定义一个小函数以将三角形的每一行收集为一个列表(并且由于您要求使用递归解,因此它也是递归定义的):
(defun upwards-range (x y &optional (by 2))
"Returns a list containing numbers from X to Y
by BY steps."
(if (>= x y)
(list y)
(cons x (upwards-range (+ x by) y by))))
(upwards-range 1 7) ; => (1 3 5 7)
第二个创建一个函数,该函数收集三角形的所有行。请注意,这里我隐含地期望参数N
是一个奇数。在下一个函数show-triangle
中,您可以断言并返回错误。
(DEFUN TRIANGLE (N)
"COLLECTS TRIANGULAR LISTS."
(IF (= -1 N)
NIL
(APPEND (TRIANGLE (- N 2))
(LIST (UPWARDS-RANGE 1 N)))))
(TRIANGLE 7) ; => ((1) (1 3) (1 3 5) (1 3 5 7))
还有打印三角形的功能:
(defun print-triangle (N)
"Makes sure that N is an odd number and prints the
rows of the triangle if so."
(assert (oddp N) (N) "~S is an even number. Please supply an odd onve" N)
(let ((rows (triangle N)))
(dolist (row rows)
(print row))))
(print-triangle 7)
返回:
(1)
(1 3)
(1 3 5)
(1 3 5 7)